aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/maps
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/maps')
-rw-r--r--main/src/cgeo/geocaching/maps/AbstractItemizedOverlay.java66
-rw-r--r--main/src/cgeo/geocaching/maps/AbstractMap.java71
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java1794
-rw-r--r--main/src/cgeo/geocaching/maps/CachesOverlay.java359
-rw-r--r--main/src/cgeo/geocaching/maps/OtherCachersOverlay.java188
-rw-r--r--main/src/cgeo/geocaching/maps/PositionOverlay.java224
-rw-r--r--main/src/cgeo/geocaching/maps/ScaleOverlay.java154
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleCacheOverlay.java116
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleCacheOverlayItem.java28
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleGeoPoint.java13
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleMapActivity.java123
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleMapController.java37
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleMapFactory.java50
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleMapProjection.java29
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleMapView.java194
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleOtherCachersOverlay.java109
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleOtherCachersOverlayItem.java44
-rw-r--r--main/src/cgeo/geocaching/maps/google/googleOverlay.java56
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java18
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/GeneralOverlay.java21
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java16
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java35
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java43
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapControllerImpl.java20
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapFactory.java32
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapProjectionImpl.java18
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java72
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/OnDragListener.java13
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/OtherCachersOverlayItemImpl.java15
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/OverlayImpl.java21
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/OverlayItemImpl.java19
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfCacheOverlay.java111
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfCacheOverlayItem.java35
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfGeoPoint.java12
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfMapActivity.java117
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfMapController.java48
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfMapFactory.java49
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfMapProjection.java29
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfMapView.java245
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfOtherCachersOverlay.java112
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfOtherCachersOverlayItem.java44
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/mfOverlay.java57
42 files changed, 4857 insertions, 0 deletions
diff --git a/main/src/cgeo/geocaching/maps/AbstractItemizedOverlay.java b/main/src/cgeo/geocaching/maps/AbstractItemizedOverlay.java
new file mode 100644
index 0000000..f1905a5
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/AbstractItemizedOverlay.java
@@ -0,0 +1,66 @@
+package cgeo.geocaching.maps;
+
+import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+import cgeo.geocaching.maps.interfaces.OverlayImpl;
+import cgeo.geocaching.maps.interfaces.OverlayItemImpl;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Base class for itemized overlays. Delegates calls from deriving classes to the contained
+ * provider-specific implementation.
+ *
+ * @author rsudev
+ *
+ */
+public abstract class AbstractItemizedOverlay implements GeneralOverlay {
+
+ private ItemizedOverlayImpl ovlImpl;
+
+ protected AbstractItemizedOverlay(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);
+ }
+
+ @Override
+ public OverlayImpl getOverlayImpl() {
+ return ovlImpl;
+ }
+
+ public abstract OverlayItemImpl createItem(int index);
+
+ public abstract int size();
+}
diff --git a/main/src/cgeo/geocaching/maps/AbstractMap.java b/main/src/cgeo/geocaching/maps/AbstractMap.java
new file mode 100644
index 0000000..4fc99a5
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/AbstractMap.java
@@ -0,0 +1,71 @@
+package cgeo.geocaching.maps;
+
+import cgeo.geocaching.maps.interfaces.MapActivityImpl;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * Base class for the map activity. Delegates base class calls to the
+ * provider-specific implementation.
+ *
+ * @author rsudev
+ *
+ */
+public abstract class AbstractMap {
+
+ MapActivityImpl mapActivity;
+
+ protected AbstractMap(MapActivityImpl 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.superOnStop();
+ }
+
+ public void onPause() {
+ mapActivity.superOnPause();
+ }
+
+ 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);
+ }
+
+ public abstract void goHome(View view);
+
+ public abstract void goManual(View view);
+
+}
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
new file mode 100644
index 0000000..9797556
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -0,0 +1,1794 @@
+package cgeo.geocaching.maps;
+
+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.cgWaypoint;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.activity.ActivityMixin;
+import cgeo.geocaching.cgSettings.mapSourceEnum;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.maps.interfaces.MapActivityImpl;
+import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapControllerImpl;
+import cgeo.geocaching.maps.interfaces.MapFactory;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.OnDragListener;
+import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.ImageSwitcher;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.ImageView.ScaleType;
+import android.widget.ViewSwitcher.ViewFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
+
+public class CGeoMap extends AbstractMap implements OnDragListener, ViewFactory {
+
+ private static final int MENU_SELECT_MAPVIEW = 1;
+ private static final int MENU_MAP_LIVE = 2;
+ private static final int MENU_STORE_CACHES = 3;
+ private static final int MENU_TRAIL_MODE = 4;
+ private static final int MENU_CIRCLE_MODE = 5;
+
+ private static final int SUBMENU_VIEW_GOOGLE_MAP = 10;
+ private static final int SUBMENU_VIEW_GOOGLE_SAT = 11;
+ private static final int SUBMENU_VIEW_MF_MAPNIK = 13;
+ private static final int SUBMENU_VIEW_MF_OSMARENDER = 14;
+ private static final int SUBMENU_VIEW_MF_CYCLEMAP = 15;
+ private static final int SUBMENU_VIEW_MF_OFFLINE = 16;
+
+ 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 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 String searchIdIntent = null;
+ private String geocodeIntent = null;
+ private Geopoint coordsIntent = null;
+ private String waypointTypeIntent = null;
+ private int[] mapStateIntent = null;
+ // status data
+ private UUID 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 usersThreadRun = 0L;
+ private volatile boolean downloaded = false;
+ // overlays
+ private CachesOverlay overlayCaches = null;
+ private OtherCachersOverlay overlayOtherCachers = null;
+ private ScaleOverlay overlayScale = null;
+ private PositionOverlay overlayPosition = null;
+ // data for overlays
+ private int cachesCnt = 0;
+ private Map<Integer, Drawable> iconsCache = new HashMap<Integer, Drawable>();
+ private List<cgCache> caches = new ArrayList<cgCache>();
+ private List<cgUser> users = new ArrayList<cgUser>();
+ private List<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 ImageSwitcher 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) {
+ 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(caches.size());
+ title.append(']');
+ }
+
+ ActivityMixin.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) {
+ ActivityMixin.showProgress(activity, false);
+ } else if (what == 1) {
+ ActivityMixin.showProgress(activity, true);
+ }
+ }
+ };
+ final private Handler loadDetailsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == 0) {
+ if (waitDialog != null) {
+ int secondsElapsed = (int) ((System.currentTimeMillis() - detailProgressTime) / 1000);
+ int secondsRemaining;
+ if (detailProgress > 0) //DP can be zero and cause devisionByZero
+ secondsRemaining = (detailTotal - detailProgress) * secondsElapsed / detailProgress;
+ else
+ secondsRemaining = (detailTotal - detailProgress) * secondsElapsed;
+
+ waitDialog.setProgress(detailProgress);
+ if (secondsRemaining < 40) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (secondsRemaining < 90) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%d", (secondsRemaining / 60)) + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%d", (secondsRemaining / 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, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate);
+ }
+ }
+ }
+ };
+ final private Handler noMapTokenHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (!noMapTokenShowed) {
+ ActivityMixin.showToast(activity, res.getString(R.string.map_token_err));
+
+ noMapTokenShowed = true;
+ }
+ }
+ };
+
+ public CGeoMap(MapActivityImpl 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, Context.MODE_PRIVATE));
+ base = new cgBase(app, settings, activity.getSharedPreferences(cgSettings.preferences, Context.MODE_PRIVATE));
+ prefsEdit = activity.getSharedPreferences(cgSettings.preferences, Context.MODE_PRIVATE).edit();
+ MapFactory mapFactory = settings.getMapFactory();
+
+ // reset status
+ noMapTokenShowed = false;
+
+ // set layout
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ // set layout
+ ActivityMixin.setTheme(activity);
+ activity.setContentView(settings.getMapFactory().getMapLayoutId());
+ ActivityMixin.setTitle(activity, res.getString(R.string.map_map));
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate);
+ }
+
+ // initialize map
+ mapView = (MapViewImpl) activity.findViewById(mapFactory.getMapViewId());
+ mapView.setMapSource(settings);
+ if (!mapView.needsScaleOverlay()) {
+ mapView.setBuiltinScale(true);
+ }
+ mapView.setBuiltInZoomControls(true);
+ mapView.displayZoomControls(true);
+ mapView.preLoad();
+ mapView.setOnDragListener(this);
+
+ // initialize overlays
+ mapView.clearOverlays();
+
+ if (overlayPosition == null) {
+ overlayPosition = mapView.createAddPositionOverlay(activity, settings);
+ }
+
+ if (settings.publicLoc > 0 && overlayOtherCachers == null) {
+ overlayOtherCachers = 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 = mapView.createAddScaleOverlay(activity, settings);
+ }
+
+ 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.getString("searchid");
+ geocodeIntent = extras.getString("geocode");
+ final double latitudeIntent = extras.getDouble("latitude");
+ final double longitudeIntent = extras.getDouble("longitude");
+ coordsIntent = new Geopoint(latitudeIntent, longitudeIntent);
+ waypointTypeIntent = extras.getString("wpttype");
+ mapStateIntent = extras.getIntArray("mapstate");
+
+ if ("".equals(searchIdIntent)) {
+ searchIdIntent = null;
+ }
+ if (coordsIntent.getLatitude() == 0.0 || coordsIntent.getLongitude() == 0.0) {
+ coordsIntent = null;
+ }
+ }
+
+ // live or death
+ if (searchIdIntent == null && geocodeIntent == null && coordsIntent == null) {
+ live = true;
+ } else {
+ live = false;
+ }
+
+ if (null == mapStateIntent) {
+ if (live) {
+ followMyLocation = true;
+ } else {
+ followMyLocation = false;
+ }
+ } else {
+ followMyLocation = 1 == mapStateIntent[3] ? true : false;
+ }
+ if (geocodeIntent != null || searchIdIntent != null || coordsIntent != null || mapStateIntent != null) {
+ centerMap(geocodeIntent, searchIdIntent, coordsIntent, mapStateIntent);
+ }
+
+ // prepare my location button
+ myLocSwitch = (ImageSwitcher) activity.findViewById(R.id.my_position);
+ myLocSwitch.setFactory(this);
+ myLocSwitch.setInAnimation(activity, android.R.anim.fade_in);
+ myLocSwitch.setOutAnimation(activity, android.R.anim.fade_out);
+ myLocSwitch.setOnClickListener(new MyLocationListener());
+ switchMyLocationButton();
+
+ startTimer();
+
+ // show the filter warning bar if the filter is set
+ if (settings.cacheType != null) {
+ String cacheType = cgBase.cacheTypesInv.get(settings.cacheType);
+ ((TextView) activity.findViewById(R.id.filter_text)).setText(cacheType);
+ activity.findViewById(R.id.filter_bar).setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ app.setAction(null);
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate);
+ }
+
+ 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) {
+
+ SubMenu submenu = menu.addSubMenu(1, MENU_SELECT_MAPVIEW, 0, res.getString(R.string.map_view_map)).setIcon(android.R.drawable.ic_menu_mapmode);
+ addMapViewMenuItems(submenu);
+
+ menu.add(0, MENU_MAP_LIVE, 0, res.getString(R.string.map_live_disable)).setIcon(R.drawable.ic_menu_notifications);
+ menu.add(0, MENU_STORE_CACHES, 0, res.getString(R.string.caches_store_offline)).setIcon(android.R.drawable.ic_menu_set_as).setEnabled(false);
+ menu.add(0, MENU_TRAIL_MODE, 0, res.getString(R.string.map_trail_hide)).setIcon(android.R.drawable.ic_menu_recent_history);
+ menu.add(0, MENU_CIRCLE_MODE, 0, res.getString(R.string.map_circles_hide)).setIcon(R.drawable.ic_menu_circle);
+
+ return true;
+ }
+
+ private void addMapViewMenuItems(final Menu menu) {
+ String[] mapViews = res.getStringArray(R.array.map_sources);
+ mapSourceEnum mapSource = settings.mapSource;
+
+ menu.add(1, SUBMENU_VIEW_GOOGLE_MAP, 0, mapViews[0]).setCheckable(true).setChecked(mapSource == mapSourceEnum.googleMap);
+ menu.add(1, SUBMENU_VIEW_GOOGLE_SAT, 0, mapViews[1]).setCheckable(true).setChecked(mapSource == mapSourceEnum.googleSat);
+ menu.add(1, SUBMENU_VIEW_MF_MAPNIK, 0, mapViews[2]).setCheckable(true).setChecked(mapSource == mapSourceEnum.mapsforgeMapnik);
+ menu.add(1, SUBMENU_VIEW_MF_OSMARENDER, 0, mapViews[3]).setCheckable(true).setChecked(mapSource == mapSourceEnum.mapsforgeOsmarender);
+ menu.add(1, SUBMENU_VIEW_MF_CYCLEMAP, 0, mapViews[4]).setCheckable(true).setChecked(mapSource == mapSourceEnum.mapsforgeCycle);
+ menu.add(1, SUBMENU_VIEW_MF_OFFLINE, 0, mapViews[5]).setCheckable(true).setChecked(mapSource == mapSourceEnum.mapsforgeOffline);
+ menu.setGroupCheckable(1, true, true);
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ MenuItem item;
+ try {
+ item = menu.findItem(MENU_TRAIL_MODE); // 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(MENU_MAP_LIVE); // 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(MENU_STORE_CACHES); // store loaded
+ if (live && !isLoading() && app.getNotOfflineCount(searchId) > 0 && caches != null && caches.size() > 0) {
+ item.setEnabled(true);
+ } else {
+ item.setEnabled(false);
+ }
+
+ item = menu.findItem(MENU_CIRCLE_MODE); // 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));
+ }
+
+ item = menu.findItem(SUBMENU_VIEW_MF_OFFLINE);
+ if (settings.hasValidMapFile()) {
+ item.setEnabled(true);
+ } else {
+ item.setEnabled(false);
+ }
+ } 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 == MENU_TRAIL_MODE) {
+ 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 == MENU_MAP_LIVE) {
+ if (settings.maplive == 1) {
+ settings.liveMapDisable();
+ } else {
+ settings.liveMapEnable();
+ }
+ liveChanged = true;
+ searchId = null;
+ searchIdIntent = null;
+ } else if (id == MENU_STORE_CACHES) {
+ if (live && !isLoading() && caches != null && !caches.isEmpty()) {
+ final List<String> geocodes = new ArrayList<String>();
+
+ List<cgCache> cachesProtected = new ArrayList<cgCache>(caches);
+ try {
+ if (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.coords != null) {
+ if (cgBase.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, oneCache.coords) && 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) {
+ ActivityMixin.showToast(activity, 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, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ Float etaTime = Float.valueOf((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 == MENU_CIRCLE_MODE) {
+ if (overlayCaches == null) {
+ return false;
+ }
+
+ overlayCaches.switchCircles();
+ mapView.invalidate();
+
+ } else if (SUBMENU_VIEW_GOOGLE_MAP <= id && SUBMENU_VIEW_MF_OFFLINE >= id) {
+
+ item.setChecked(true);
+ mapSourceEnum mapSource = getMapSourceFromMenuId(id);
+
+ boolean mapRestartRequired = switchMapSource(mapSource);
+
+ if (mapRestartRequired) {
+ // close old mapview
+ activity.finish();
+
+ // prepare information to restart a similar view
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+
+ mapIntent.putExtra("detail", fromDetailIntent);
+ mapIntent.putExtra("searchid", searchIdIntent);
+ mapIntent.putExtra("geocode", geocodeIntent);
+ if (coordsIntent != null) {
+ mapIntent.putExtra("latitude", coordsIntent.getLatitude());
+ mapIntent.putExtra("longitude", coordsIntent.getLongitude());
+ }
+ mapIntent.putExtra("wpttype", waypointTypeIntent);
+ int[] mapState = new int[4];
+ GeoPointImpl mapCenter = mapView.getMapViewCenter();
+ mapState[0] = mapCenter.getLatitudeE6();
+ mapState[1] = mapCenter.getLongitudeE6();
+ mapState[2] = mapView.getMapZoomLevel();
+ mapState[3] = followMyLocation ? 1 : 0;
+ mapIntent.putExtra("mapstate", mapState);
+
+ // start the new map
+ activity.startActivity(mapIntent);
+
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private static mapSourceEnum getMapSourceFromMenuId(int menuItemId) {
+
+ switch (menuItemId) {
+ case SUBMENU_VIEW_GOOGLE_MAP:
+ return mapSourceEnum.googleMap;
+ case SUBMENU_VIEW_GOOGLE_SAT:
+ return mapSourceEnum.googleSat;
+ case SUBMENU_VIEW_MF_OSMARENDER:
+ return mapSourceEnum.mapsforgeOsmarender;
+ case SUBMENU_VIEW_MF_MAPNIK:
+ return mapSourceEnum.mapsforgeMapnik;
+ case SUBMENU_VIEW_MF_CYCLEMAP:
+ return mapSourceEnum.mapsforgeCycle;
+ case SUBMENU_VIEW_MF_OFFLINE:
+ return mapSourceEnum.mapsforgeOffline;
+ default:
+ return mapSourceEnum.googleMap;
+ }
+ }
+
+ private boolean switchMapSource(mapSourceEnum mapSource) {
+
+ settings.mapSource = mapSource;
+
+ prefsEdit.putInt("mapsource", settings.mapSource.ordinal());
+ prefsEdit.commit();
+
+ boolean mapRestartRequired = settings.mapSource.isGoogleMapSource() != settings.mapSourceUsed.isGoogleMapSource();
+
+ if (!mapRestartRequired) {
+ mapView.setMapSource(settings);
+ }
+
+ return mapRestartRequired;
+ }
+
+ private void savePrefs() {
+ if (mapView == null) {
+ return;
+ }
+
+ if (prefsEdit == null) {
+ prefsEdit = activity.getSharedPreferences(cgSettings.preferences, Context.MODE_PRIVATE).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.coordsNow);
+ }
+
+ // class: update location
+ private class UpdateLoc extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ boolean repaintRequired = false;
+
+ if (overlayPosition == null && mapView != null) {
+ overlayPosition = mapView.createAddPositionOverlay(activity, settings);
+ }
+
+ if (overlayPosition != null && geo.location != null) {
+ overlayPosition.setCoordinates(geo.location);
+ }
+
+ if (geo.coordsNow != null) {
+ if (followMyLocation) {
+ myLocationInMiddle();
+ } else {
+ repaintRequired = true;
+ }
+ }
+
+ if (settings.useCompass == 0 || (geo.speedNow != null && geo.speedNow > 5)) { // use GPS when speed is higher than 18 km/h
+ if (geo.bearingNow != null) {
+ overlayPosition.setHeading(geo.bearingNow);
+ } else {
+ overlayPosition.setHeading(0f);
+ }
+ repaintRequired = true;
+ }
+
+ if (repaintRequired && mapView != null) {
+ mapView.repaintRequired(overlayPosition);
+ }
+
+ } 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 (overlayPosition != null && mapView != null && (geo == null || geo.speedNow == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h
+ overlayPosition.setHeading(dir.directionNow);
+ mapView.invalidate();
+ }
+ }
+ }
+
+ public void startTimer() {
+ if (coordsIntent != 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()
+ || !cgBase.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
+ ) && !cgBase.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 (fromDetailIntent || StringUtils.isNotEmpty(searchIdIntent)) {
+ searchId = UUID.fromString(searchIdIntent);
+ } else {
+ if (!live || 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 in live map and stored caches are found / disables are also shown.
+ if (live && settings.maplive >= 1) {
+ final boolean excludeMine = settings.excludeMine > 0;
+ final boolean excludeDisabled = settings.excludeDisabled > 0;
+
+ for (int i = caches.size() - 1; i >= 0; i--) {
+ cgCache cache = caches.get(i);
+ if ((cache.found && excludeMine) || (cache.own && excludeMine) || (cache.disabled && excludeDisabled)) {
+ caches.remove(i);
+ }
+ }
+
+ }
+
+ 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 (live && 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;
+
+ 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;
+ }
+
+ Map<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 List<cgCache> cachesProtected = new ArrayList<cgCache>(caches);
+ final List<CachesOverlayItemImpl> items = new ArrayList<CachesOverlayItemImpl>();
+
+ if (cachesProtected != null && !cachesProtected.isEmpty()) {
+ int icon = 0;
+ Drawable pin = null;
+ CachesOverlayItemImpl item = null;
+
+ for (cgCache cacheOne : cachesProtected) {
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ if (cacheOne.coords == null) {
+ continue;
+ }
+
+ final cgCoord coord = new cgCoord(cacheOne);
+ coordinates.add(coord);
+
+ item = settings.getMapFactory().getCachesOverlayItem(coord, cacheOne.type);
+ icon = cgBase.getMarkerIcon(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);
+ }
+
+ 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.coords == null) {
+ continue;
+ }
+
+ cgCoord coord = new cgCoord(oneWaypoint);
+
+ coordinates.add(coord);
+ item = settings.getMapFactory().getCachesOverlayItem(coord, null);
+
+ icon = cgBase.getMarkerIcon(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 List<cgUser> users = null;
+
+ public DisplayUsersThread(List<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
+ List<OtherCachersOverlayItemImpl> items = new ArrayList<OtherCachersOverlayItemImpl>();
+
+ int counter = 0;
+ OtherCachersOverlayItemImpl item = null;
+
+ for (cgUser userOne : users) {
+ if (stop) {
+ return;
+ }
+
+ if (userOne.coords == null) {
+ continue;
+ }
+
+ item = settings.getMapFactory().getOtherCachersOverlayItemBase(activity, userOne);
+ items.add(item);
+
+ counter++;
+ if ((counter % 10) == 0) {
+ overlayOtherCachers.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ }
+
+ overlayOtherCachers.updateItems(items);
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display one point
+ private class DisplayPointThread extends Thread {
+
+ @Override
+ public void run() {
+ if (mapView == null || caches == null) {
+ return;
+ }
+
+ if (coordsIntent != null) {
+ cgCoord coord = new cgCoord();
+ coord.type = "waypoint";
+ coord.coords = coordsIntent;
+ coord.name = "some place";
+
+ coordinates.add(coord);
+ CachesOverlayItemImpl item = settings.getMapFactory().getCachesOverlayItem(coord, null);
+
+ final int icon = cgBase.getMarkerIcon(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 List<String> geocodes = null;
+ private volatile boolean stop = false;
+ private long last = 0L;
+
+ public LoadDetails(Handler handlerIn, List<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) {
+ 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) {
+ 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(final Geopoint coords) {
+ if (coords == null) {
+ return;
+ }
+ if (mapView == null) {
+ return;
+ }
+
+ if (!alreadyCentered) {
+ alreadyCentered = true;
+
+ mapController.setCenter(makeGeoPoint(coords));
+ } else {
+ mapController.animateTo(makeGeoPoint(coords));
+ }
+ }
+
+ // move map to view results of searchIdIntent
+ private void centerMap(String geocodeCenter, String searchIdCenter, final Geopoint coordsCenter, int[] mapState) {
+
+ if (!centered && mapState != null) {
+ try {
+ mapController.setCenter(settings.getMapFactory().getGeoPointBase(new Geopoint(mapState[0] / 1.0e6, mapState[1] / 1.0e6)));
+ mapController.setZoom(mapState[2]);
+ } catch (Exception e) {
+ // nothing at all
+ }
+
+ centered = true;
+ alreadyCentered = true;
+ } else if (!centered && (geocodeCenter != null || searchIdIntent != null)) {
+ try {
+ List<Object> viewport = null;
+
+ if (geocodeCenter != null) {
+ viewport = app.getBounds(geocodeCenter);
+ } else {
+ viewport = app.getBounds(UUID.fromString(searchIdCenter));
+ }
+
+ if (viewport == null)
+ return;
+
+ Integer cnt = (Integer) viewport.get(0);
+ Integer minLat = null;
+ Integer maxLat = null;
+ Integer minLon = null;
+ Integer maxLon = null;
+
+ if (viewport.get(1) != null) {
+ minLat = (int) ((Double) viewport.get(1) * 1e6);
+ }
+ if (viewport.get(2) != null) {
+ maxLat = (int) ((Double) viewport.get(2) * 1e6);
+ }
+ if (viewport.get(3) != null) {
+ maxLon = (int) ((Double) viewport.get(3) * 1e6);
+ }
+ if (viewport.get(4) != null) {
+ minLon = (int) ((Double) viewport.get(4) * 1e6);
+ }
+
+ 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(new Geopoint(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 && coordsCenter != null) {
+ try {
+ mapController.setCenter(makeGeoPoint(coordsCenter));
+ } catch (Exception e) {
+ // nothing at all
+ }
+
+ centered = true;
+ alreadyCentered = true;
+ }
+ }
+
+ // switch My Location button image
+ private void switchMyLocationButton() {
+ if (followMyLocation) {
+ myLocSwitch.setImageResource(R.drawable.actionbar_mylocation_on);
+ myLocationInMiddle();
+ } else {
+ myLocSwitch.setImageResource(R.drawable.actionbar_mylocation_off);
+ }
+ }
+
+ // set my location listener
+ private class MyLocationListener implements View.OnClickListener {
+ public void onClick(View view) {
+ followMyLocation = !followMyLocation;
+ switchMyLocationButton();
+ }
+ }
+
+ @Override
+ public void onDrag() {
+ if (followMyLocation) {
+ followMyLocation = false;
+ switchMyLocationButton();
+ }
+ }
+
+ // make geopoint
+ private GeoPointImpl makeGeoPoint(final Geopoint coords) {
+ return settings.getMapFactory().getGeoPointBase(coords);
+ }
+
+ // close activity and open homescreen
+ public void goHome(View view) {
+ ActivityMixin.goHome(activity);
+ }
+
+ // open manual entry
+ public void goManual(View view) {
+ ActivityMixin.goManual(activity, "c:geo-live-map");
+ }
+
+ @Override
+ public View makeView() {
+ ImageView imageView = new ImageView(activity);
+ imageView.setScaleType(ScaleType.CENTER);
+ imageView.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
+ return imageView;
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/CachesOverlay.java b/main/src/cgeo/geocaching/maps/CachesOverlay.java
new file mode 100644
index 0000000..cae4448
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/CachesOverlay.java
@@ -0,0 +1,359 @@
+package cgeo.geocaching.maps;
+
+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.geopoint.Geopoint;
+import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.maps.interfaces.MapFactory;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Canvas;
+import android.graphics.DashPathEffect;
+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 java.util.ArrayList;
+import java.util.List;
+
+public class CachesOverlay extends AbstractItemizedOverlay implements GeneralOverlay {
+
+ private List<CachesOverlayItemImpl> items = new ArrayList<CachesOverlayItemImpl>();
+ 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;
+ private MapFactory mapFactory = null;
+
+ public CachesOverlay(cgSettings settingsIn, ItemizedOverlayImpl ovlImpl, Context contextIn, Boolean fromDetailIn) {
+ super(ovlImpl);
+
+ populate();
+ settings = settingsIn;
+
+ context = contextIn;
+ fromDetail = fromDetailIn;
+
+ mapFactory = settings.getMapFactory();
+ }
+
+ public void updateItems(CachesOverlayItemImpl item) {
+ List<CachesOverlayItemImpl> itemsPre = new ArrayList<CachesOverlayItemImpl>();
+ itemsPre.add(item);
+
+ updateItems(itemsPre);
+ }
+
+ public void updateItems(List<CachesOverlayItemImpl> itemsPre) {
+ if (itemsPre == null) {
+ return;
+ }
+
+ for (CachesOverlayItemImpl item : itemsPre) {
+ item.setMarker(boundCenterBottom(item.getMarker(0)));
+ }
+
+ // ensure no interference between the draw and content changing routines
+ getOverlayImpl().lock();
+ try {
+ items = new ArrayList<CachesOverlayItemImpl>(itemsPre);
+
+ setLastFocusedItemIndex(-1); // to reset tap during data change
+ populate();
+ } finally {
+ getOverlayImpl().unlock();
+ }
+ }
+
+ 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) {
+
+ // prevent content changes
+ getOverlayImpl().lock();
+ try {
+ if (displayCircles) {
+ if (blockedCircle == null) {
+ blockedCircle = new Paint();
+ blockedCircle.setAntiAlias(true);
+ blockedCircle.setStrokeWidth(1.0f);
+ blockedCircle.setARGB(127, 0, 0, 0);
+ blockedCircle.setPathEffect(new DashPathEffect(new float[] { 3, 2 }, 0));
+ }
+
+ 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 (CachesOverlayItemImpl item : items) {
+ final cgCoord itemCoord = item.getCoord();
+ float[] result = new float[1];
+
+ Location.distanceBetween(itemCoord.coords.getLatitude(), itemCoord.coords.getLongitude(),
+ itemCoord.coords.getLatitude(), itemCoord.coords.getLongitude() + 1, result);
+ final float longitudeLineDistance = result[0];
+
+ GeoPointImpl itemGeo = mapFactory.getGeoPointBase(itemCoord.coords);
+
+ final Geopoint leftCoords = new Geopoint(itemCoord.coords.getLatitude(),
+ itemCoord.coords.getLongitude() - 161 / longitudeLineDistance);
+ GeoPointImpl leftGeo = mapFactory.getGeoPointBase(leftCoords);
+
+ 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);
+ }
+ } finally {
+ getOverlayImpl().unlock();
+ }
+ }
+
+ @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();
+
+ CachesOverlayItemImpl item = null;
+
+ // prevent concurrent changes
+ getOverlayImpl().lock();
+ try {
+ if (index < items.size()) {
+ item = items.get(index);
+ }
+ } finally {
+ getOverlayImpl().unlock();
+ }
+
+ if (item == null) {
+ return false;
+ }
+
+ cgCoord coordinate = item.getCoord();
+
+ if (StringUtils.isNotBlank(coordinate.type) && coordinate.type.equalsIgnoreCase("cache") && StringUtils.isNotBlank(coordinate.geocode)) {
+ 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") && 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 CachesOverlayItemImpl 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 CachesOverlayItemImpl 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)) {
+ 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.clear();
+ cgeonavigate.coordinates.add(coordinate);
+
+ Intent navigateIntent = new Intent(context, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coordinate.coords.getLatitude());
+ navigateIntent.putExtra("longitude", coordinate.coords.getLongitude());
+ navigateIntent.putExtra("geocode", coordinate.geocode.toUpperCase());
+ context.startActivity(navigateIntent);
+ dialog.cancel();
+ }
+ });
+ }
+ } else {
+ dialog.setTitle("waypoint");
+
+ String waypointType;
+ if (cgBase.cacheTypesInv.containsKey(coordinate.typeSpec)) {
+ 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.clear();
+ cgeonavigate.coordinates.add(coordinate);
+
+ Intent navigateIntent = new Intent(context, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coordinate.coords.getLatitude());
+ navigateIntent.putExtra("longitude", coordinate.coords.getLongitude());
+ 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/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java
new file mode 100644
index 0000000..4eff80b
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java
@@ -0,0 +1,188 @@
+package cgeo.geocaching.maps;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.cgeodetail;
+import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl;
+
+import org.apache.commons.lang3.StringUtils;
+
+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 java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class OtherCachersOverlay extends AbstractItemizedOverlay implements GeneralOverlay {
+
+ private List<OtherCachersOverlayItemImpl> items = new ArrayList<OtherCachersOverlayItemImpl>();
+ private Context context = null;
+ private final Pattern patternGeocode = Pattern.compile("^(GC[A-Z0-9]+)(\\: ?(.+))?$", Pattern.CASE_INSENSITIVE);
+
+ public OtherCachersOverlay(ItemizedOverlayImpl ovlImplIn, Context contextIn) {
+ super(ovlImplIn);
+ populate();
+
+ context = contextIn;
+ }
+
+ protected void updateItems(OtherCachersOverlayItemImpl item) {
+ List<OtherCachersOverlayItemImpl> itemsPre = new ArrayList<OtherCachersOverlayItemImpl>();
+ itemsPre.add(item);
+
+ updateItems(itemsPre);
+ }
+
+ public void updateItems(List<OtherCachersOverlayItemImpl> itemsPre) {
+ if (itemsPre == null) {
+ return;
+ }
+
+ for (OtherCachersOverlayItemImpl item : itemsPre) {
+ item.setMarker(boundCenter(item.getMarker(0)));
+ }
+
+ items.clear();
+
+ if (itemsPre.size() > 0) {
+ items = new ArrayList<OtherCachersOverlayItemImpl>(itemsPre);
+ }
+
+ setLastFocusedItemIndex(-1); // to reset tap during data change
+ populate();
+ }
+
+ @Override
+ public boolean onTap(int index) {
+ try {
+ if (items.size() <= index) {
+ return false;
+ }
+
+ final OtherCachersOverlayItemImpl 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()) {
+ 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")) {
+ icon = R.drawable.client_cgeo;
+ } else if (user.client.equalsIgnoreCase("preCaching")) {
+ icon = R.drawable.client_precaching;
+ } else if (user.client.equalsIgnoreCase("Handy Geocaching")) {
+ 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 (StringUtils.isNotBlank(geocode)) {
+ 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 OtherCachersOverlayItemImpl 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/main/src/cgeo/geocaching/maps/PositionOverlay.java b/main/src/cgeo/geocaching/maps/PositionOverlay.java
new file mode 100644
index 0000000..8099400
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/PositionOverlay.java
@@ -0,0 +1,224 @@
+package cgeo.geocaching.maps;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapFactory;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+import cgeo.geocaching.maps.interfaces.OverlayImpl;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Point;
+import android.location.Location;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PositionOverlay implements GeneralOverlay {
+ private cgSettings settings = null;
+ private Location coordinates = null;
+ private GeoPointImpl location = null;
+ private Float heading = 0f;
+ 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 widthArrowHalf = 0;
+ private int heightArrowHalf = 0;
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+ private Location historyRecent = null;
+ private List<Location> history = new ArrayList<Location>();
+ private Point historyPointN = new Point();
+ private Point historyPointP = new Point();
+ private Activity activity;
+ private MapFactory mapFactory = null;
+ private OverlayImpl ovlImpl = null;
+
+ public PositionOverlay(cgSettings settingsIn, Activity activity, OverlayImpl ovlImpl) {
+ settings = settingsIn;
+ this.activity = activity;
+ this.mapFactory = settings.getMapFactory();
+ this.ovlImpl = ovlImpl;
+ }
+
+ public void setCoordinates(Location coordinatesIn) {
+ coordinates = coordinatesIn;
+ location = settings.getMapFactory().getGeoPointBase(new Geopoint(coordinates));
+ }
+
+ public void setHeading(Float bearingNow) {
+ heading = bearingNow;
+ }
+
+ @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;
+
+ 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];
+
+ final Geopoint leftCoords = new Geopoint(latitude, longitude - accuracy / longitudeLineDistance);
+ GeoPointImpl leftGeo = mapFactory.getGeoPointBase(leftCoords);
+ 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 && historyRecent.distanceTo(coordinates) > 5.0) || 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(new Geopoint(prev)), historyPointP);
+ projection.toPixels(mapFactory.getGeoPointBase(new Geopoint(now)), historyPointN);
+
+ if ((alphaCnt - cnt) > 0) {
+ alpha = 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(new Geopoint(prev)), historyPointP);
+ projection.toPixels(mapFactory.getGeoPointBase(new Geopoint(now)), 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(activity.getResources(), R.drawable.my_location_chevron);
+ widthArrowHalf = arrow.getWidth() / 2;
+ heightArrowHalf = arrow.getHeight() / 2;
+ }
+
+ int marginLeft;
+ int marginTop;
+
+ marginLeft = center.x - widthArrowHalf;
+ marginTop = center.y - heightArrowHalf;
+
+ Matrix matrix = new Matrix();
+ matrix.setRotate(heading.floatValue(), widthArrowHalf, heightArrowHalf);
+ matrix.postTranslate(marginLeft, marginTop);
+
+ canvas.drawBitmap(arrow, matrix, null);
+
+ canvas.setDrawFilter(remfil);
+
+ //super.draw(canvas, mapView, shadow);
+ }
+
+ @Override
+ public OverlayImpl getOverlayImpl() {
+ return this.ovlImpl;
+ }
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/maps/ScaleOverlay.java b/main/src/cgeo/geocaching/maps/ScaleOverlay.java
new file mode 100644
index 0000000..d958597
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/ScaleOverlay.java
@@ -0,0 +1,154 @@
+package cgeo.geocaching.maps;
+
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgSettings.mapSourceEnum;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+import cgeo.geocaching.maps.interfaces.OverlayImpl;
+
+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;
+
+public class ScaleOverlay implements GeneralOverlay {
+ 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;
+ private OverlayImpl ovlImpl = null;
+
+ public ScaleOverlay(Activity activity, cgSettings settingsIn, OverlayImpl overlayImpl) {
+ settings = settingsIn;
+ this.ovlImpl = overlayImpl;
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ pixelDensity = metrics.density;
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // Scale overlay is only necessary for google maps, so the mapsforge
+ // related draw method needs not to be filled.
+ }
+
+ @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.0; // pixels related to following latitude span
+ bottom = mapView.getHeight() - 14; // pixels from bottom side of screen
+
+ final Geopoint leftCoords = new Geopoint(center.getLatitudeE6() / 1e6, center.getLongitudeE6() / 1e6 - span / 2);
+ final Geopoint rightCoords = new Geopoint(center.getLatitudeE6() / 1e6, center.getLongitudeE6() / 1e6 + span / 2);
+
+ distance = leftCoords.distanceTo(rightCoords) / 2;
+ distanceRound = 0d;
+
+ if (settings.units == cgSettings.unitsImperial) {
+ distance /= cgBase.miles2km;
+
+ 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 (mapSourceEnum.googleSat == settings.mapSource) {
+ 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);
+ }
+
+ @Override
+ public OverlayImpl getOverlayImpl() {
+ return ovlImpl;
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleCacheOverlay.java b/main/src/cgeo/geocaching/maps/google/googleCacheOverlay.java
new file mode 100644
index 0000000..b175842
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleCacheOverlay.java
@@ -0,0 +1,116 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.maps.CachesOverlay;
+import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+
+import com.google.android.maps.ItemizedOverlay;
+import com.google.android.maps.MapView;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Google specific implementation of the itemized cache overlay
+ *
+ * @author rsudev
+ *
+ */
+public class googleCacheOverlay extends ItemizedOverlay<googleCacheOverlayItem> implements ItemizedOverlayImpl {
+
+ private CachesOverlay base;
+ private Lock lock = new ReentrantLock();
+
+ public googleCacheOverlay(cgSettings settingsIn, Context contextIn, Drawable markerIn, Boolean fromDetailIn) {
+ super(boundCenterBottom(markerIn));
+ base = new CachesOverlay(settingsIn, this, contextIn, fromDetailIn);
+ }
+
+ @Override
+ public CachesOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected googleCacheOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (googleCacheOverlayItem) base.createItem(i);
+ }
+
+ @Override
+ public int size() {
+ if (base == null)
+ return 0;
+
+ return base.size();
+ }
+
+ @Override
+ protected boolean onTap(int arg0) {
+ if (base == null)
+ return false;
+
+ return base.onTap(arg0);
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapView mapView, boolean shadow) {
+ base.draw(canvas, (MapViewImpl) mapView, shadow);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ super.setLastFocusedIndex(i);
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ super.draw(canvas, (MapView) mapView, shadow);
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // Nothing to do here...
+ }
+
+ @Override
+ public void lock() {
+ lock.lock();
+ }
+
+ @Override
+ public void unlock() {
+ lock.unlock();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/google/googleCacheOverlayItem.java
new file mode 100644
index 0000000..001dab9
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleCacheOverlayItem.java
@@ -0,0 +1,28 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.OverlayItem;
+
+public class googleCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl {
+ private String cacheType = null;
+ private cgCoord coord;
+
+ public googleCacheOverlayItem(cgCoord coordinate, String type) {
+ super(new GeoPoint(coordinate.coords.getLatitudeE6(), coordinate.coords.getLongitudeE6()), coordinate.name, "");
+
+ this.cacheType = type;
+ this.coord = coordinate;
+ }
+
+ public cgCoord getCoord() {
+ return coord;
+ }
+
+ public String getType() {
+ return cacheType;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleGeoPoint.java b/main/src/cgeo/geocaching/maps/google/googleGeoPoint.java
new file mode 100644
index 0000000..18cca20
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleGeoPoint.java
@@ -0,0 +1,13 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+
+import com.google.android.maps.GeoPoint;
+
+public class googleGeoPoint extends GeoPoint implements GeoPointImpl {
+
+ public googleGeoPoint(int latitudeE6, int longitudeE6) {
+ super(latitudeE6, longitudeE6);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleMapActivity.java b/main/src/cgeo/geocaching/maps/google/googleMapActivity.java
new file mode 100644
index 0000000..a094064
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleMapActivity.java
@@ -0,0 +1,123 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.maps.AbstractMap;
+import cgeo.geocaching.maps.CGeoMap;
+import cgeo.geocaching.maps.interfaces.MapActivityImpl;
+
+import com.google.android.maps.MapActivity;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+public class googleMapActivity extends MapActivity implements MapActivityImpl {
+
+ private AbstractMap mapBase;
+
+ public googleMapActivity() {
+ mapBase = new CGeoMap(this);
+ }
+
+ @Override
+ protected boolean isRouteDisplayed() {
+ return false;
+ }
+
+ @Override
+ public Activity getActivity() {
+ return this;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ mapBase.onCreate(icicle);
+ }
+
+ @Override
+ protected void onDestroy() {
+ mapBase.onDestroy();
+ }
+
+ @Override
+ protected void onPause() {
+ mapBase.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ mapBase.onResume();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ return mapBase.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return mapBase.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ return mapBase.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ protected void onStop() {
+ mapBase.onStop();
+ }
+
+ @Override
+ public void superOnCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public boolean superOnCreateOptionsMenu(Menu menu) {
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public void superOnDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean superOnOptionsItemSelected(MenuItem item) {
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void superOnResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void superOnStop() {
+ super.onStop();
+ }
+
+ @Override
+ public void superOnPause() {
+ super.onPause();
+ }
+
+ @Override
+ public boolean superOnPrepareOptionsMenu(Menu menu) {
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ // close activity and open homescreen
+ public void goHome(View view) {
+ mapBase.goHome(view);
+ }
+
+ // open manual entry
+ public void goManual(View view) {
+ mapBase.goManual(view);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleMapController.java b/main/src/cgeo/geocaching/maps/google/googleMapController.java
new file mode 100644
index 0000000..cc607cc
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleMapController.java
@@ -0,0 +1,37 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapControllerImpl;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.MapController;
+
+public class googleMapController implements MapControllerImpl {
+
+ private MapController mapController;
+
+ public googleMapController(MapController mapControllerIn) {
+ mapController = mapControllerIn;
+ }
+
+ @Override
+ public void animateTo(GeoPointImpl geoPoint) {
+ mapController.animateTo((GeoPoint) geoPoint);
+ }
+
+ @Override
+ public void setCenter(GeoPointImpl geoPoint) {
+ mapController.setCenter((GeoPoint) geoPoint);
+ }
+
+ @Override
+ public void setZoom(int mapzoom) {
+ mapController.setZoom(mapzoom);
+ }
+
+ @Override
+ public void zoomToSpan(int latSpanE6, int lonSpanE6) {
+ mapController.zoomToSpan(latSpanE6, lonSpanE6);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleMapFactory.java b/main/src/cgeo/geocaching/maps/google/googleMapFactory.java
new file mode 100644
index 0000000..c7eb33e
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleMapFactory.java
@@ -0,0 +1,50 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapFactory;
+import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl;
+
+import com.google.android.maps.MapActivity;
+
+import android.content.Context;
+
+public class googleMapFactory implements MapFactory {
+
+ @Override
+ public Class<? extends MapActivity> getMapClass() {
+ return googleMapActivity.class;
+ }
+
+ @Override
+ public int getMapViewId() {
+ return R.id.map;
+ }
+
+ @Override
+ public int getMapLayoutId() {
+ return R.layout.googlemap;
+ }
+
+ @Override
+ public GeoPointImpl getGeoPointBase(final Geopoint coords) {
+ return new googleGeoPoint(coords.getLatitudeE6(), coords.getLongitudeE6());
+ }
+
+ @Override
+ public CachesOverlayItemImpl getCachesOverlayItem(cgCoord coordinate, String type) {
+ googleCacheOverlayItem baseItem = new googleCacheOverlayItem(coordinate, type);
+ return baseItem;
+ }
+
+ @Override
+ public OtherCachersOverlayItemImpl getOtherCachersOverlayItemBase(Context context, cgUser userOne) {
+ googleOtherCachersOverlayItem baseItem = new googleOtherCachersOverlayItem(context, userOne);
+ return baseItem;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleMapProjection.java b/main/src/cgeo/geocaching/maps/google/googleMapProjection.java
new file mode 100644
index 0000000..761f509
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleMapProjection.java
@@ -0,0 +1,29 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.Projection;
+
+import android.graphics.Point;
+
+public class googleMapProjection implements MapProjectionImpl {
+
+ private Projection projection;
+
+ public googleMapProjection(Projection projectionIn) {
+ projection = projectionIn;
+ }
+
+ @Override
+ public void toPixels(GeoPointImpl leftGeo, Point left) {
+ projection.toPixels((GeoPoint) leftGeo, left);
+ }
+
+ @Override
+ public Object getImpl() {
+ return projection;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleMapView.java b/main/src/cgeo/geocaching/maps/google/googleMapView.java
new file mode 100644
index 0000000..5b07cdf
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleMapView.java
@@ -0,0 +1,194 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.maps.PositionOverlay;
+import cgeo.geocaching.maps.CachesOverlay;
+import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.OtherCachersOverlay;
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapControllerImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.OnDragListener;
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+import cgeo.geocaching.maps.interfaces.OverlayImpl;
+import cgeo.geocaching.maps.interfaces.OverlayImpl.overlayType;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.MapView;
+import com.google.android.maps.Overlay;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.MotionEvent;
+
+public class googleMapView extends MapView implements MapViewImpl {
+ private GestureDetector gestureDetector;
+ private OnDragListener onDragListener;
+
+ public googleMapView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ gestureDetector = new GestureDetector(context, new GestureListener());
+ }
+
+ public googleMapView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ gestureDetector = new GestureDetector(context, new GestureListener());
+ }
+
+ public googleMapView(Context context, String apiKey) {
+ super(context, apiKey);
+ gestureDetector = new GestureDetector(context, new GestureListener());
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ try {
+ if (getMapZoomLevel() >= 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
+ getController().setZoom(22);
+ }
+
+ super.draw(canvas);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapView.draw: " + e.toString());
+ }
+ }
+
+ @Override
+ public void displayZoomControls(boolean takeFocus) {
+ try {
+ super.displayZoomControls(takeFocus);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapView.displayZoomControls: " + e.toString());
+ }
+ }
+
+ @Override
+ public MapControllerImpl getMapController() {
+ return new googleMapController(getController());
+ }
+
+ @Override
+ public GeoPointImpl getMapViewCenter() {
+ GeoPoint point = getMapCenter();
+ return new googleGeoPoint(point.getLatitudeE6(), point.getLongitudeE6());
+ }
+
+ @Override
+ public void addOverlay(OverlayImpl ovl) {
+ getOverlays().add((Overlay) ovl);
+ }
+
+ @Override
+ public void clearOverlays() {
+ getOverlays().clear();
+ }
+
+ @Override
+ public MapProjectionImpl getMapProjection() {
+ return new googleMapProjection(getProjection());
+ }
+
+ @Override
+ public CachesOverlay createAddMapOverlay(cgSettings settings,
+ Context context, Drawable drawable, boolean fromDetailIntent) {
+
+ googleCacheOverlay ovl = new googleCacheOverlay(settings, context, drawable, fromDetailIntent);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public OtherCachersOverlay createAddUsersOverlay(Context context, Drawable markerIn) {
+ googleOtherCachersOverlay ovl = new googleOtherCachersOverlay(context, markerIn);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public PositionOverlay createAddPositionOverlay(Activity activity,
+ cgSettings settingsIn) {
+
+ googleOverlay ovl = new googleOverlay(activity, settingsIn, overlayType.PositionOverlay);
+ getOverlays().add(ovl);
+ return (PositionOverlay) ovl.getBase();
+ }
+
+ @Override
+ public ScaleOverlay createAddScaleOverlay(Activity activity,
+ cgSettings settingsIn) {
+
+ googleOverlay ovl = new googleOverlay(activity, settingsIn, overlayType.ScaleOverlay);
+ getOverlays().add(ovl);
+ return (ScaleOverlay) ovl.getBase();
+ }
+
+ @Override
+ public int getMapZoomLevel() {
+ return getZoomLevel();
+ }
+
+ @Override
+ public void setMapSource(cgSettings settings) {
+
+ switch (settings.mapSource) {
+ case googleSat:
+ setSatellite(true);
+ break;
+ default:
+ setSatellite(false);
+ }
+ }
+
+ @Override
+ public boolean needsScaleOverlay() {
+ return true;
+ }
+
+ @Override
+ public void setBuiltinScale(boolean b) {
+ //Nothing to do for google maps...
+ }
+
+ @Override
+ public void repaintRequired(GeneralOverlay overlay) {
+ invalidate();
+ }
+
+ @Override
+ public void setOnDragListener(OnDragListener onDragListener) {
+ this.onDragListener = onDragListener;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ gestureDetector.onTouchEvent(ev);
+ return super.onTouchEvent(ev);
+ }
+
+ private class GestureListener extends SimpleOnGestureListener {
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ getController().zoomInFixing((int) e.getX(), (int) e.getY());
+ if (onDragListener != null) {
+ onDragListener.onDrag();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2,
+ float distanceX, float distanceY) {
+ if (onDragListener != null) {
+ onDragListener.onDrag();
+ }
+ return super.onScroll(e1, e2, distanceX, distanceY);
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleOtherCachersOverlay.java b/main/src/cgeo/geocaching/maps/google/googleOtherCachersOverlay.java
new file mode 100644
index 0000000..11df0b7
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleOtherCachersOverlay.java
@@ -0,0 +1,109 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.maps.OtherCachersOverlay;
+import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+
+import com.google.android.maps.ItemizedOverlay;
+import com.google.android.maps.MapView;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class googleOtherCachersOverlay extends ItemizedOverlay<googleOtherCachersOverlayItem> implements ItemizedOverlayImpl {
+
+ private OtherCachersOverlay base;
+ private Lock lock = new ReentrantLock();
+
+ public googleOtherCachersOverlay(Context contextIn, Drawable markerIn) {
+ super(boundCenter(markerIn));
+ base = new OtherCachersOverlay(this, contextIn);
+ }
+
+ @Override
+ public OtherCachersOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected googleOtherCachersOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (googleOtherCachersOverlayItem) base.createItem(i);
+ }
+
+ @Override
+ public int size() {
+ if (base == null)
+ return 0;
+
+ return base.size();
+ }
+
+ @Override
+ protected boolean onTap(int arg0) {
+ if (base == null)
+ return false;
+
+ return base.onTap(arg0);
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapView mapView, boolean shadow) {
+ base.draw(canvas, (MapViewImpl) mapView, shadow);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ super.setLastFocusedIndex(i);
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ super.draw(canvas, (MapView) mapView, shadow);
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // Nothing to do here
+ }
+
+ @Override
+ public void lock() {
+ lock.lock();
+ }
+
+ @Override
+ public void unlock() {
+ lock.unlock();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleOtherCachersOverlayItem.java b/main/src/cgeo/geocaching/maps/google/googleOtherCachersOverlayItem.java
new file mode 100644
index 0000000..d1aa635
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleOtherCachersOverlayItem.java
@@ -0,0 +1,44 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.OverlayItem;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+public class googleOtherCachersOverlayItem extends OverlayItem implements OtherCachersOverlayItemImpl {
+ private Context context = null;
+ private cgUser user = null;
+
+ public googleOtherCachersOverlayItem(Context contextIn, cgUser userIn) {
+ super(new GeoPoint(userIn.coords.getLatitudeE6(), userIn.coords.getLongitudeE6()), userIn.username, "");
+
+ context = contextIn;
+ user = userIn;
+ }
+
+ @Override
+ public Drawable getMarker(int state) {
+ Drawable marker = null;
+
+ if (user != null && user.located != null && user.located.getTime() >= (System.currentTimeMillis() - (20 * 60 * 1000))) {
+ marker = context.getResources().getDrawable(R.drawable.user_location_active);
+ } else {
+ marker = context.getResources().getDrawable(R.drawable.user_location);
+ }
+
+ marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight());
+ marker.setAlpha(190);
+ setMarker(marker);
+
+ return marker;
+ }
+
+ public cgUser getUser() {
+ return user;
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/google/googleOverlay.java b/main/src/cgeo/geocaching/maps/google/googleOverlay.java
new file mode 100644
index 0000000..1d7eb1c
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/google/googleOverlay.java
@@ -0,0 +1,56 @@
+package cgeo.geocaching.maps.google;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.maps.PositionOverlay;
+import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+import cgeo.geocaching.maps.interfaces.OverlayImpl;
+
+import com.google.android.maps.MapView;
+import com.google.android.maps.Overlay;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class googleOverlay extends Overlay implements OverlayImpl {
+
+ private GeneralOverlay overlayBase = null;
+ private Lock lock = new ReentrantLock();
+
+ public googleOverlay(Activity activityIn, cgSettings settingsIn, overlayType ovlType) {
+ switch (ovlType) {
+ case PositionOverlay:
+ overlayBase = new PositionOverlay(settingsIn, activityIn, this);
+ break;
+ case ScaleOverlay:
+ overlayBase = new ScaleOverlay(activityIn, settingsIn, this);
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapView mapView, boolean shadow) {
+ super.draw(canvas, mapView, shadow);
+
+ if (overlayBase != null) {
+ overlayBase.draw(canvas, (MapViewImpl) mapView, shadow);
+ }
+ }
+
+ public GeneralOverlay getBase() {
+ return overlayBase;
+ }
+
+ @Override
+ public void lock() {
+ lock.lock();
+ }
+
+ @Override
+ public void unlock() {
+ lock.unlock();
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java b/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java
new file mode 100644
index 0000000..59e79a0
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java
@@ -0,0 +1,18 @@
+package cgeo.geocaching.maps.interfaces;
+
+import cgeo.geocaching.cgCoord;
+
+/**
+ * Covers the common functions of the provider-specific
+ * CacheOverlayItem implementations
+ *
+ * @author rsudev
+ *
+ */
+public interface CachesOverlayItemImpl extends OverlayItemImpl {
+
+ public cgCoord getCoord();
+
+ public String getType();
+
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/GeneralOverlay.java b/main/src/cgeo/geocaching/maps/interfaces/GeneralOverlay.java
new file mode 100644
index 0000000..35d0b2d
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/GeneralOverlay.java
@@ -0,0 +1,21 @@
+package cgeo.geocaching.maps.interfaces;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+
+/**
+ * Defines the base functions of the provider-independent
+ * Overlay implementations
+ *
+ * @author rsudev
+ *
+ */
+public interface GeneralOverlay {
+
+ void draw(Canvas canvas, MapViewImpl mapView, boolean shadow);
+
+ void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel);
+
+ OverlayImpl getOverlayImpl();
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java b/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java
new file mode 100644
index 0000000..55f014b
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java
@@ -0,0 +1,16 @@
+package cgeo.geocaching.maps.interfaces;
+
+/**
+ * Defines the common functions of the provider-specific
+ * GeoPoint implementations
+ *
+ * @author rsudev
+ *
+ */
+public interface GeoPointImpl {
+
+ int getLatitudeE6();
+
+ int getLongitudeE6();
+
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java b/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java
new file mode 100644
index 0000000..8f9dba2
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/ItemizedOverlayImpl.java
@@ -0,0 +1,35 @@
+package cgeo.geocaching.maps.interfaces;
+
+import cgeo.geocaching.maps.AbstractItemizedOverlay;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Defines the common functions to access the provider-specific
+ * ItemizedOverlay implementation
+ *
+ * @author rsudev
+ *
+ */
+public interface ItemizedOverlayImpl extends OverlayImpl {
+
+ AbstractItemizedOverlay getBase();
+
+ void superPopulate();
+
+ void superSetLastFocusedItemIndex(int i);
+
+ Drawable superBoundCenter(Drawable markerIn);
+
+ Drawable superBoundCenterBottom(Drawable marker);
+
+ boolean superOnTap(int index);
+
+ void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow);
+
+ void superDrawOverlayBitmap(Canvas canvas, Point drawPosition, MapProjectionImpl projection,
+ byte drawZoomLevel);
+
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java
new file mode 100644
index 0000000..ff7e338
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java
@@ -0,0 +1,43 @@
+package cgeo.geocaching.maps.interfaces;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * Defines the common functions of the provider-specific
+ * MapActivity implementations.
+ *
+ * @author rsudev
+ *
+ */
+public interface MapActivityImpl {
+
+ Resources getResources();
+
+ Activity getActivity();
+
+ void superOnCreate(Bundle savedInstanceState);
+
+ void superOnResume();
+
+ void superOnDestroy();
+
+ void superOnStop();
+
+ void superOnPause();
+
+ boolean superOnCreateOptionsMenu(Menu menu);
+
+ boolean superOnPrepareOptionsMenu(Menu menu);
+
+ boolean superOnOptionsItemSelected(MenuItem item);
+
+ public abstract void goHome(View view);
+
+ public abstract void goManual(View view);
+
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapControllerImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapControllerImpl.java
new file mode 100644
index 0000000..86a5800
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapControllerImpl.java
@@ -0,0 +1,20 @@
+package cgeo.geocaching.maps.interfaces;
+
+/**
+ * Defines the common functions of the provider-specific
+ * MapController implementations
+ *
+ * @author rsudev
+ *
+ */
+public interface MapControllerImpl {
+
+ void setZoom(int mapzoom);
+
+ void setCenter(GeoPointImpl geoPoint);
+
+ void animateTo(GeoPointImpl geoPoint);
+
+ void zoomToSpan(int latSpanE6, int lonSpanE6);
+
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapFactory.java b/main/src/cgeo/geocaching/maps/interfaces/MapFactory.java
new file mode 100644
index 0000000..0e21f2a
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapFactory.java
@@ -0,0 +1,32 @@
+package cgeo.geocaching.maps.interfaces;
+
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.geopoint.Geopoint;
+
+import android.app.Activity;
+import android.content.Context;
+
+/**
+ * Defines functions of a factory class to get implementation specific objects
+ * (GeoPoints, OverlayItems, ...)
+ *
+ * @author rsudev
+ *
+ */
+public interface MapFactory {
+
+ public Class<? extends Activity> getMapClass();
+
+ public int getMapViewId();
+
+ public int getMapLayoutId();
+
+ public GeoPointImpl getGeoPointBase(final Geopoint coords);
+
+ CachesOverlayItemImpl getCachesOverlayItem(cgCoord coordinate, String type);
+
+ public OtherCachersOverlayItemImpl getOtherCachersOverlayItemBase(Context context,
+ cgUser userOne);
+
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapProjectionImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapProjectionImpl.java
new file mode 100644
index 0000000..c7b6856
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapProjectionImpl.java
@@ -0,0 +1,18 @@
+package cgeo.geocaching.maps.interfaces;
+
+import android.graphics.Point;
+
+/**
+ * Defines common functions of the provider-specific
+ * MapProjection implementations
+ *
+ * @author rsudev
+ *
+ */
+public interface MapProjectionImpl {
+
+ Object getImpl();
+
+ void toPixels(GeoPointImpl leftGeo, Point left);
+
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
new file mode 100644
index 0000000..e13e2e9
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
@@ -0,0 +1,72 @@
+package cgeo.geocaching.maps.interfaces;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.maps.PositionOverlay;
+import cgeo.geocaching.maps.CachesOverlay;
+import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.OtherCachersOverlay;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Defines common functions of the provider-specific
+ * MapView implementations
+ *
+ * @author rsudev
+ *
+ */
+public interface MapViewImpl {
+
+ void invalidate();
+
+ void setBuiltInZoomControls(boolean b);
+
+ void displayZoomControls(boolean b);
+
+ void preLoad();
+
+ void clearOverlays();
+
+ void addOverlay(OverlayImpl ovl);
+
+ MapControllerImpl getMapController();
+
+ void destroyDrawingCache();
+
+ GeoPointImpl getMapViewCenter();
+
+ int getLatitudeSpan();
+
+ int getLongitudeSpan();
+
+ int getMapZoomLevel();
+
+ int getWidth();
+
+ int getHeight();
+
+ MapProjectionImpl getMapProjection();
+
+ Context getContext();
+
+ CachesOverlay createAddMapOverlay(cgSettings settings, Context context,
+ Drawable drawable, boolean fromDetailIntent);
+
+ OtherCachersOverlay createAddUsersOverlay(Context context, Drawable markerIn);
+
+ ScaleOverlay createAddScaleOverlay(Activity activity, cgSettings settingsIn);
+
+ PositionOverlay createAddPositionOverlay(Activity activity, cgSettings settingsIn);
+
+ boolean needsScaleOverlay();
+
+ void setBuiltinScale(boolean b);
+
+ void setMapSource(cgSettings settings);
+
+ void repaintRequired(GeneralOverlay overlay);
+
+ void setOnDragListener(OnDragListener onDragListener);
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/OnDragListener.java b/main/src/cgeo/geocaching/maps/interfaces/OnDragListener.java
new file mode 100644
index 0000000..285aafa
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/OnDragListener.java
@@ -0,0 +1,13 @@
+package cgeo.geocaching.maps.interfaces;
+
+/**
+ * Notifies the parent class when a MapView has been dragged
+ *
+ * @author cachapa
+ *
+ */
+public interface OnDragListener {
+
+ public void onDrag();
+
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/OtherCachersOverlayItemImpl.java b/main/src/cgeo/geocaching/maps/interfaces/OtherCachersOverlayItemImpl.java
new file mode 100644
index 0000000..43fc58e
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/OtherCachersOverlayItemImpl.java
@@ -0,0 +1,15 @@
+package cgeo.geocaching.maps.interfaces;
+
+import cgeo.geocaching.cgUser;
+
+/**
+ * Common functions of the provider-specific
+ * UserOverlayItem implementations
+ *
+ * @author rsudev
+ *
+ */
+public interface OtherCachersOverlayItemImpl extends OverlayItemImpl {
+
+ public cgUser getUser();
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/OverlayImpl.java b/main/src/cgeo/geocaching/maps/interfaces/OverlayImpl.java
new file mode 100644
index 0000000..926873b
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/OverlayImpl.java
@@ -0,0 +1,21 @@
+package cgeo.geocaching.maps.interfaces;
+
+/**
+ * Marker interface of the provider-specific
+ * Overlay implementations
+ *
+ * @author rsudev
+ *
+ */
+public interface OverlayImpl {
+
+ public enum overlayType {
+ PositionOverlay,
+ ScaleOverlay
+ }
+
+ void lock();
+
+ void unlock();
+
+}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/OverlayItemImpl.java b/main/src/cgeo/geocaching/maps/interfaces/OverlayItemImpl.java
new file mode 100644
index 0000000..1673da2
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/interfaces/OverlayItemImpl.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.maps.interfaces;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * Common functions of the provider-specific
+ * OverlayItem implementations
+ *
+ * @author rsudev
+ *
+ */
+public interface OverlayItemImpl {
+
+ public String getTitle();
+
+ public Drawable getMarker(int index);
+
+ public void setMarker(Drawable markerIn);
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfCacheOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/mfCacheOverlay.java
new file mode 100644
index 0000000..507f1e5
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfCacheOverlay.java
@@ -0,0 +1,111 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.maps.CachesOverlay;
+import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+
+import org.mapsforge.android.maps.ItemizedOverlay;
+import org.mapsforge.android.maps.Projection;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class mfCacheOverlay extends ItemizedOverlay<mfCacheOverlayItem> implements ItemizedOverlayImpl {
+
+ private CachesOverlay base;
+ private Lock lock = new ReentrantLock();
+
+ public mfCacheOverlay(cgSettings settingsIn, Context contextIn, Drawable markerIn, Boolean fromDetailIn) {
+ super(boundCenterBottom(markerIn));
+ base = new CachesOverlay(settingsIn, this, contextIn, fromDetailIn);
+ }
+
+ @Override
+ public CachesOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected mfCacheOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (mfCacheOverlayItem) base.createItem(i);
+ }
+
+ @Override
+ public int size() {
+ if (base == null)
+ return 0;
+
+ return base.size();
+ }
+
+ @Override
+ protected boolean onTap(int arg0) {
+ if (base == null)
+ return false;
+
+ return base.onTap(arg0);
+ }
+
+ @Override
+ protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+ base.drawOverlayBitmap(canvas, drawPosition, new mfMapProjection(projection), drawZoomLevel);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ // nothing to do
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ // nothing to do here...
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ super.drawOverlayBitmap(canvas, drawPosition, (Projection) projection.getImpl(), drawZoomLevel);
+ }
+
+ @Override
+ public void lock() {
+ lock.lock();
+ }
+
+ @Override
+ public void unlock() {
+ lock.unlock();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/mapsforge/mfCacheOverlayItem.java
new file mode 100644
index 0000000..b52ecd8
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfCacheOverlayItem.java
@@ -0,0 +1,35 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.OverlayItem;
+
+import android.graphics.drawable.Drawable;
+
+public class mfCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl {
+ private String cacheType = null;
+ private cgCoord coord;
+
+ public mfCacheOverlayItem(cgCoord coordinate, String type) {
+ super(new GeoPoint(coordinate.coords.getLatitudeE6(), coordinate.coords.getLongitudeE6()), coordinate.name, "");
+
+ this.cacheType = type;
+ this.coord = coordinate;
+ }
+
+ public cgCoord getCoord() {
+ return coord;
+ }
+
+ public String getType() {
+ return cacheType;
+ }
+
+ @Override
+ public Drawable getMarker(int index) {
+ return getMarker();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfGeoPoint.java b/main/src/cgeo/geocaching/maps/mapsforge/mfGeoPoint.java
new file mode 100644
index 0000000..0e47008
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfGeoPoint.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+
+import org.mapsforge.android.maps.GeoPoint;
+
+public class mfGeoPoint extends GeoPoint implements GeoPointImpl {
+
+ public mfGeoPoint(int latitudeE6, int longitudeE6) {
+ super(latitudeE6, longitudeE6);
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfMapActivity.java b/main/src/cgeo/geocaching/maps/mapsforge/mfMapActivity.java
new file mode 100644
index 0000000..6c423b0
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfMapActivity.java
@@ -0,0 +1,117 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.maps.AbstractMap;
+import cgeo.geocaching.maps.CGeoMap;
+import cgeo.geocaching.maps.interfaces.MapActivityImpl;
+
+import org.mapsforge.android.maps.MapActivity;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+public class mfMapActivity extends MapActivity implements MapActivityImpl {
+
+ private AbstractMap mapBase;
+
+ public mfMapActivity() {
+ mapBase = new CGeoMap(this);
+ }
+
+ @Override
+ public Activity getActivity() {
+ return this;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ mapBase.onCreate(icicle);
+ }
+
+ @Override
+ protected void onDestroy() {
+ mapBase.onDestroy();
+ }
+
+ @Override
+ protected void onPause() {
+ mapBase.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ mapBase.onResume();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ return mapBase.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return mapBase.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ return mapBase.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ protected void onStop() {
+ mapBase.onStop();
+ }
+
+ @Override
+ public void superOnCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public boolean superOnCreateOptionsMenu(Menu menu) {
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public void superOnDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean superOnOptionsItemSelected(MenuItem item) {
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void superOnResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void superOnStop() {
+ super.onStop();
+ }
+
+ @Override
+ public void superOnPause() {
+ super.onPause();
+ }
+
+ @Override
+ public boolean superOnPrepareOptionsMenu(Menu menu) {
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ // close activity and open homescreen
+ public void goHome(View view) {
+ mapBase.goHome(view);
+ }
+
+ // open manual entry
+ public void goManual(View view) {
+ mapBase.goManual(view);
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfMapController.java b/main/src/cgeo/geocaching/maps/mapsforge/mfMapController.java
new file mode 100644
index 0000000..da7d9be
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfMapController.java
@@ -0,0 +1,48 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapControllerImpl;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.MapController;
+
+public class mfMapController implements MapControllerImpl {
+
+ private MapController mapController;
+ private int maxZoomLevel;
+
+ public mfMapController(MapController mapControllerIn, int maxZoomLevelIn) {
+ mapController = mapControllerIn;
+ maxZoomLevel = maxZoomLevelIn;
+ }
+
+ @Override
+ public void animateTo(GeoPointImpl geoPoint) {
+ mapController.setCenter((GeoPoint) geoPoint);
+ }
+
+ @Override
+ public void setCenter(GeoPointImpl geoPoint) {
+ mapController.setCenter((GeoPoint) geoPoint);
+ }
+
+ @Override
+ public void setZoom(int mapzoom) {
+ int mfzoom = mapzoom - 1;
+ if (mfzoom > maxZoomLevel) {
+ mfzoom = maxZoomLevel;
+ }
+ mapController.setZoom(mfzoom);
+ }
+
+ @Override
+ public void zoomToSpan(int latSpanE6, int lonSpanE6) {
+
+ if (latSpanE6 != 0 && lonSpanE6 != 0) {
+ // calculate zoomlevel
+ int distDegree = Math.max(latSpanE6, lonSpanE6);
+ int zoomLevel = (int) Math.floor(Math.log(360.0 * 1e6 / distDegree) / Math.log(2));
+ mapController.setZoom(zoomLevel + 1);
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfMapFactory.java b/main/src/cgeo/geocaching/maps/mapsforge/mfMapFactory.java
new file mode 100644
index 0000000..d713b22
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfMapFactory.java
@@ -0,0 +1,49 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapFactory;
+import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl;
+
+import android.app.Activity;
+import android.content.Context;
+
+public class mfMapFactory implements MapFactory {
+
+ @Override
+ public Class<? extends Activity> getMapClass() {
+ return mfMapActivity.class;
+ }
+
+ @Override
+ public int getMapViewId() {
+ return R.id.mfmap;
+ }
+
+ @Override
+ public int getMapLayoutId() {
+ return R.layout.mfmap;
+ }
+
+ @Override
+ public GeoPointImpl getGeoPointBase(final Geopoint coords) {
+ return new mfGeoPoint(coords.getLatitudeE6(), coords.getLongitudeE6());
+ }
+
+ @Override
+ public CachesOverlayItemImpl getCachesOverlayItem(cgCoord coordinate, String type) {
+ mfCacheOverlayItem baseItem = new mfCacheOverlayItem(coordinate, type);
+ return baseItem;
+ }
+
+ @Override
+ public OtherCachersOverlayItemImpl getOtherCachersOverlayItemBase(Context context, cgUser userOne) {
+ mfOtherCachersOverlayItem baseItem = new mfOtherCachersOverlayItem(context, userOne);
+ return baseItem;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfMapProjection.java b/main/src/cgeo/geocaching/maps/mapsforge/mfMapProjection.java
new file mode 100644
index 0000000..74a6c0b
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfMapProjection.java
@@ -0,0 +1,29 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.Projection;
+
+import android.graphics.Point;
+
+public class mfMapProjection implements MapProjectionImpl {
+
+ private Projection projection;
+
+ public mfMapProjection(Projection projectionIn) {
+ projection = projectionIn;
+ }
+
+ @Override
+ public void toPixels(GeoPointImpl leftGeo, Point left) {
+ projection.toPixels((GeoPoint) leftGeo, left);
+ }
+
+ @Override
+ public Object getImpl() {
+ return projection;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfMapView.java b/main/src/cgeo/geocaching/maps/mapsforge/mfMapView.java
new file mode 100644
index 0000000..6200079
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfMapView.java
@@ -0,0 +1,245 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.maps.PositionOverlay;
+import cgeo.geocaching.maps.CachesOverlay;
+import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.OtherCachersOverlay;
+import cgeo.geocaching.maps.interfaces.GeoPointImpl;
+import cgeo.geocaching.maps.interfaces.MapControllerImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+import cgeo.geocaching.maps.interfaces.OnDragListener;
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+import cgeo.geocaching.maps.interfaces.OverlayImpl;
+import cgeo.geocaching.maps.interfaces.OverlayImpl.overlayType;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.MapDatabase;
+import org.mapsforge.android.maps.MapView;
+import org.mapsforge.android.maps.MapViewMode;
+import org.mapsforge.android.maps.Overlay;
+import org.mapsforge.android.maps.Projection;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.MotionEvent;
+
+public class mfMapView extends MapView implements MapViewImpl {
+ private GestureDetector gestureDetector;
+ private OnDragListener onDragListener;
+
+ public mfMapView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ gestureDetector = new GestureDetector(context, new GestureListener());
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ try {
+ if (getMapZoomLevel() >= 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
+ getController().setZoom(22);
+ }
+
+ super.draw(canvas);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapView.draw: " + e.toString());
+ }
+ }
+
+ @Override
+ public void displayZoomControls(boolean takeFocus) {
+ // nothing to do here
+ }
+
+ @Override
+ public MapControllerImpl getMapController() {
+ return new mfMapController(getController(), getMaxZoomLevel());
+ }
+
+ @Override
+ public GeoPointImpl getMapViewCenter() {
+ GeoPoint point = getMapCenter();
+ return new mfGeoPoint(point.getLatitudeE6(), point.getLongitudeE6());
+ }
+
+ @Override
+ public void addOverlay(OverlayImpl ovl) {
+ getOverlays().add((Overlay) ovl);
+ }
+
+ @Override
+ public void clearOverlays() {
+ getOverlays().clear();
+ }
+
+ @Override
+ public MapProjectionImpl getMapProjection() {
+ return new mfMapProjection(getProjection());
+ }
+
+ @Override
+ public CachesOverlay createAddMapOverlay(cgSettings settings,
+ Context context, Drawable drawable, boolean fromDetailIntent) {
+
+ mfCacheOverlay ovl = new mfCacheOverlay(settings, context, drawable, fromDetailIntent);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public OtherCachersOverlay createAddUsersOverlay(Context context, Drawable markerIn) {
+ mfOtherCachersOverlay ovl = new mfOtherCachersOverlay(context, markerIn);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public PositionOverlay createAddPositionOverlay(Activity activity,
+ cgSettings settingsIn) {
+ mfOverlay ovl = new mfOverlay(activity, settingsIn, overlayType.PositionOverlay);
+ getOverlays().add(ovl);
+ return (PositionOverlay) ovl.getBase();
+ }
+
+ @Override
+ public ScaleOverlay createAddScaleOverlay(Activity activity,
+ cgSettings settingsIn) {
+ mfOverlay ovl = new mfOverlay(activity, settingsIn, overlayType.ScaleOverlay);
+ getOverlays().add(ovl);
+ return (ScaleOverlay) ovl.getBase();
+ }
+
+ @Override
+ public int getLatitudeSpan() {
+
+ int span = 0;
+
+ Projection projection = getProjection();
+
+ if (projection != null && getHeight() > 0) {
+
+ GeoPoint low = projection.fromPixels(0, 0);
+ GeoPoint high = projection.fromPixels(0, getHeight());
+
+ if (low != null && high != null) {
+ span = Math.abs(high.getLatitudeE6() - low.getLatitudeE6());
+ }
+ }
+
+ return span;
+ }
+
+ @Override
+ public int getLongitudeSpan() {
+
+ int span = 0;
+
+ Projection projection = getProjection();
+
+ if (projection != null && getWidth() > 0) {
+ GeoPoint low = projection.fromPixels(0, 0);
+ GeoPoint high = projection.fromPixels(getWidth(), 0);
+
+ if (low != null && high != null) {
+ span = Math.abs(high.getLongitudeE6() - low.getLongitudeE6());
+ }
+ }
+
+ return span;
+ }
+
+ @Override
+ public void preLoad() {
+ // Nothing to do here
+ }
+
+ @Override
+ public int getMapZoomLevel() {
+ return getZoomLevel() + 1;
+ }
+
+ @Override
+ public boolean needsScaleOverlay() {
+ return false;
+ }
+
+ @Override
+ public void setBuiltinScale(boolean b) {
+ setScaleBar(b);
+ }
+
+ @Override
+ public void setMapSource(cgSettings settings) {
+
+ switch (settings.mapSource) {
+ case mapsforgeOsmarender:
+ setMapViewMode(MapViewMode.OSMARENDER_TILE_DOWNLOAD);
+ break;
+ case mapsforgeCycle:
+ setMapViewMode(MapViewMode.OPENCYCLEMAP_TILE_DOWNLOAD);
+ break;
+ case mapsforgeOffline:
+ if (MapDatabase.isValidMapFile(settings.getMapFile())) {
+ setMapViewMode(MapViewMode.CANVAS_RENDERER);
+ super.setMapFile(settings.getMapFile());
+ } else {
+ setMapViewMode(MapViewMode.MAPNIK_TILE_DOWNLOAD);
+ }
+ break;
+ default:
+ setMapViewMode(MapViewMode.MAPNIK_TILE_DOWNLOAD);
+ }
+ }
+
+ @Override
+ public void repaintRequired(GeneralOverlay overlay) {
+
+ try {
+ mfOverlay ovl = (mfOverlay) overlay.getOverlayImpl();
+
+ if (ovl != null) {
+ ovl.requestRedraw();
+ }
+
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "mfMapView.repaintRequired: " + e.toString());
+ }
+ }
+
+ @Override
+ public void setOnDragListener(OnDragListener onDragListener) {
+ this.onDragListener = onDragListener;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ gestureDetector.onTouchEvent(ev);
+ return super.onTouchEvent(ev);
+ }
+
+ private class GestureListener extends SimpleOnGestureListener {
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ if (onDragListener != null) {
+ onDragListener.onDrag();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2,
+ float distanceX, float distanceY) {
+ if (onDragListener != null) {
+ onDragListener.onDrag();
+ }
+ return super.onScroll(e1, e2, distanceX, distanceY);
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfOtherCachersOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/mfOtherCachersOverlay.java
new file mode 100644
index 0000000..fc545cc
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfOtherCachersOverlay.java
@@ -0,0 +1,112 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.maps.OtherCachersOverlay;
+import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+
+import org.mapsforge.android.maps.ItemizedOverlay;
+import org.mapsforge.android.maps.Projection;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class mfOtherCachersOverlay extends ItemizedOverlay<mfOtherCachersOverlayItem> implements ItemizedOverlayImpl {
+
+ private OtherCachersOverlay base;
+ private Lock lock = new ReentrantLock();
+
+ public mfOtherCachersOverlay(Context contextIn, Drawable markerIn) {
+ super(boundCenter(markerIn));
+ base = new OtherCachersOverlay(this, contextIn);
+ }
+
+ @Override
+ public OtherCachersOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected mfOtherCachersOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (mfOtherCachersOverlayItem) base.createItem(i);
+ }
+
+ @Override
+ public int size() {
+ if (base == null)
+ return 0;
+
+ return base.size();
+ }
+
+ @Override
+ protected boolean onTap(int arg0) {
+ if (base == null)
+ return false;
+
+ return base.onTap(arg0);
+ }
+
+ @Override
+ protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+
+ base.drawOverlayBitmap(canvas, drawPosition, new mfMapProjection(projection), drawZoomLevel);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ // Nothing to do here
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ // Nothing to do here
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+
+ super.drawOverlayBitmap(canvas, drawPosition, (Projection) projection.getImpl(), drawZoomLevel);
+ }
+
+ @Override
+ public void lock() {
+ lock.lock();
+ }
+
+ @Override
+ public void unlock() {
+ lock.unlock();
+ }
+
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfOtherCachersOverlayItem.java b/main/src/cgeo/geocaching/maps/mapsforge/mfOtherCachersOverlayItem.java
new file mode 100644
index 0000000..4845425
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfOtherCachersOverlayItem.java
@@ -0,0 +1,44 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.OverlayItem;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+public class mfOtherCachersOverlayItem extends OverlayItem implements OtherCachersOverlayItemImpl {
+ private Context context = null;
+ private cgUser user = null;
+
+ public mfOtherCachersOverlayItem(Context contextIn, cgUser userIn) {
+ super(new GeoPoint((int) (userIn.coords.getLatitudeE6()), userIn.coords.getLongitudeE6()), userIn.username, "");
+
+ context = contextIn;
+ user = userIn;
+ }
+
+ @Override
+ public Drawable getMarker(int state) {
+ Drawable marker = null;
+
+ if (user != null && user.located != null && user.located.getTime() >= (System.currentTimeMillis() - (20 * 60 * 1000))) {
+ marker = context.getResources().getDrawable(R.drawable.user_location_active);
+ } else {
+ marker = context.getResources().getDrawable(R.drawable.user_location);
+ }
+
+ marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight());
+ marker.setAlpha(190);
+ setMarker(marker);
+
+ return marker;
+ }
+
+ public cgUser getUser() {
+ return user;
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/mfOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/mfOverlay.java
new file mode 100644
index 0000000..a2ea3f4
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/mapsforge/mfOverlay.java
@@ -0,0 +1,57 @@
+package cgeo.geocaching.maps.mapsforge;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.maps.PositionOverlay;
+import cgeo.geocaching.maps.ScaleOverlay;
+import cgeo.geocaching.maps.interfaces.GeneralOverlay;
+import cgeo.geocaching.maps.interfaces.OverlayImpl;
+
+import org.mapsforge.android.maps.Overlay;
+import org.mapsforge.android.maps.Projection;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Point;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class mfOverlay extends Overlay implements OverlayImpl {
+
+ private GeneralOverlay overlayBase = null;
+ private Lock lock = new ReentrantLock();
+
+ public mfOverlay(Activity activityIn, cgSettings settingsIn, OverlayImpl.overlayType ovlType) {
+
+ switch (ovlType) {
+ case PositionOverlay:
+ overlayBase = new PositionOverlay(settingsIn, activityIn, this);
+ break;
+ case ScaleOverlay:
+ overlayBase = new ScaleOverlay(activityIn, settingsIn, this);
+ }
+ }
+
+ @Override
+ protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+
+ if (overlayBase != null) {
+ overlayBase.drawOverlayBitmap(canvas, drawPosition, new mfMapProjection(projection), drawZoomLevel);
+ }
+ }
+
+ public GeneralOverlay getBase() {
+ return overlayBase;
+ }
+
+ @Override
+ public void lock() {
+ lock.lock();
+ }
+
+ @Override
+ public void unlock() {
+ lock.unlock();
+ }
+}