diff options
Diffstat (limited to 'main/src/cgeo/geocaching/maps')
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(); + } +} |
