aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo
diff options
context:
space:
mode:
authorblafoo <github@blafoo.de>2012-03-07 23:12:55 +0100
committerblafoo <github@blafoo.de>2012-03-07 23:12:55 +0100
commitd6477fcae75ce1de889246b7fb789c56aa25cc56 (patch)
tree12cbcde5b4da48fef337e807761507b74682e130 /main/src/cgeo
parent734d52565d401abb9701f5e5efbb278745021e03 (diff)
downloadcgeo-d6477fcae75ce1de889246b7fb789c56aa25cc56.zip
cgeo-d6477fcae75ce1de889246b7fb789c56aa25cc56.tar.gz
cgeo-d6477fcae75ce1de889246b7fb789c56aa25cc56.tar.bz2
Live Map strategy. Closes #1183
Diffstat (limited to 'main/src/cgeo')
-rw-r--r--main/src/cgeo/geocaching/Settings.java17
-rw-r--r--main/src/cgeo/geocaching/cgeo.java9
-rw-r--r--main/src/cgeo/geocaching/cgeoapplication.java4
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCBase.java62
-rw-r--r--main/src/cgeo/geocaching/connector/gc/Tile.java67
-rw-r--r--main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java58
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java42
7 files changed, 235 insertions, 24 deletions
diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java
index 1a58a85..40ad96d 100644
--- a/main/src/cgeo/geocaching/Settings.java
+++ b/main/src/cgeo/geocaching/Settings.java
@@ -1,6 +1,7 @@
package cgeo.geocaching;
import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.maps.MapProviderFactory;
import cgeo.geocaching.maps.interfaces.MapProvider;
@@ -78,6 +79,7 @@ public final class Settings {
private static final String KEY_DEBUG_INFORMATIONS = "debuginfos";
private static final String KEY_DEFAULT_NAVIGATION_TOOL = "defaultNavigationTool";
private static final String KEY_DEFAULT_NAVIGATION_TOOL_2 = "defaultNavigationTool2";
+ private static final String KEY_LIVE_MAP_STRATEGY = "livemapstrategy";
private final static int unitsMetric = 1;
private final static int unitsImperial = 2;
@@ -1013,4 +1015,19 @@ public final class Settings {
}
});
}
+
+ public static Strategy getLiveMapStrategy() {
+ return Strategy.getById(sharedPrefs.getInt(KEY_LIVE_MAP_STRATEGY, Strategy.AUTO.id));
+ }
+
+ public static void setLiveMapStrategy(final Strategy strategy) {
+ editSharedSettings(new PrefRunnable() {
+
+ @Override
+ public void edit(Editor edit) {
+ edit.putInt(KEY_LIVE_MAP_STRATEGY, strategy.id);
+ }
+ });
+ }
+
}
diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/cgeo.java
index 2ce5f6d..03184b3 100644
--- a/main/src/cgeo/geocaching/cgeo.java
+++ b/main/src/cgeo/geocaching/cgeo.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.enumerations.WaypointType;
@@ -469,6 +470,9 @@ public class cgeo extends AbstractActivity {
for (WaypointType waypointType : WaypointType.values()) {
waypointType.setL10n();
}
+ for (Strategy strategy : Strategy.values()) {
+ strategy.setL10n();
+ }
Settings.getLogin();
@@ -599,10 +603,11 @@ public class cgeo extends AbstractActivity {
navType.setText(res.getString(geo.locationProvider.resourceId));
if (geo.accuracyNow >= 0) {
+ int speed = Math.round(geo.speedNow) * 60 * 60 / 1000;
if (Settings.isUseMetricUnits()) {
- navAccuracy.setText("±" + Math.round(geo.accuracyNow) + " m");
+ navAccuracy.setText("±" + Math.round(geo.accuracyNow) + " m" + Formatter.SEPARATOR + speed + " km/h");
} else {
- navAccuracy.setText("±" + Math.round(geo.accuracyNow * IConversion.METERS_TO_FEET) + " ft");
+ navAccuracy.setText("±" + Math.round(geo.accuracyNow * IConversion.METERS_TO_FEET) + " ft" + Formatter.SEPARATOR + speed / IConversion.MILES_TO_KILOMETER + " mph");
}
} else {
navAccuracy.setText(null);
diff --git a/main/src/cgeo/geocaching/cgeoapplication.java b/main/src/cgeo/geocaching/cgeoapplication.java
index a986dba..e2b39d8 100644
--- a/main/src/cgeo/geocaching/cgeoapplication.java
+++ b/main/src/cgeo/geocaching/cgeoapplication.java
@@ -144,6 +144,10 @@ public class cgeoapplication extends Application {
return geo;
}
+ public float getSpeedFromGeo() {
+ return geo != null ? geo.speedNow : 0f;
+ }
+
public cgGeo removeGeo() {
if (geo != null) {
geo.replaceUpdate(null);
diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java
index a4664aa..9174c4a 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCBase.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java
@@ -4,12 +4,17 @@ import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Settings;
import cgeo.geocaching.cgBase;
import cgeo.geocaching.cgCache;
+import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
+import cgeo.geocaching.enumerations.LiveMapStrategy.StrategyFlag;
+import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.utils.BaseUtils;
import cgeo.geocaching.utils.LeastRecentlyUsedCache;
import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.SetUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.json.JSONArray;
@@ -21,8 +26,10 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* GC.com/Groundspeak (GS) specific stuff
@@ -58,15 +65,24 @@ public class GCBase {
/**
* @param viewport
- * @param zoomlevel
- * initial zoomlevel
- * @param autoAdjust
- * Auto-adjust zoomlevel
* @param sessionToken
* @return
*/
public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens) {
+ Strategy strategy = Settings.getLiveMapStrategy();
+ if (strategy == Strategy.AUTO) {
+ float speedNow = cgeoapplication.getInstance().getSpeedFromGeo();
+ strategy = speedNow >= 8 ? Strategy.FASTEST : Strategy.DETAILED; // 8 m/s = 30 km/h
+ }
+ return searchByViewport(viewport, tokens, strategy);
+ }
+ /**
+ * @param viewport
+ * @param sessionToken
+ * @return
+ */
+ public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens, Strategy strategy) {
Log.d(Settings.tag, "GCBase.searchByViewport" + viewport.toString());
String referer = GCConstants.URL_LIVE_MAP;
@@ -74,7 +90,7 @@ public class GCBase {
final SearchResult searchResult = new SearchResult();
searchResult.setUrl(referer + "?ll=" + viewport.getCenter().getLatitude() + "," + viewport.getCenter().getLongitude());
- List<Tile> tiles = getTilesForViewport(viewport);
+ Set<Tile> tiles = strategy.flags.contains(StrategyFlag.LOAD_TILES) ? getTilesForViewport(viewport) : SetUtils.EMPTY_SET;
for (Tile tile : tiles) {
StringBuilder url = new StringBuilder();
@@ -114,7 +130,7 @@ public class GCBase {
if (StringUtils.isEmpty(data)) {
Log.e(Settings.tag, "GCBase.searchByViewport: No data from server for tile (" + tile.getX() + "/" + tile.getY() + ")");
} else {
- final SearchResult search = parseMapJSON(data, tile, bitmap);
+ final SearchResult search = parseMapJSON(data, tile, bitmap, strategy);
if (search == null || CollectionUtils.isEmpty(search.getGeocodes())) {
Log.e(Settings.tag, "GCBase.searchByViewport: No cache parsed for viewport " + viewport);
}
@@ -124,9 +140,11 @@ public class GCBase {
}
}
- SearchResult search = cgBase.searchByCoords(null, viewport.getCenter(), Settings.getCacheType(), false);
- if (search != null) {
- searchResult.addGeocodes(search.getGeocodes());
+ if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY)) {
+ SearchResult search = cgBase.searchByCoords(null, viewport.getCenter(), Settings.getCacheType(), false);
+ if (search != null) {
+ searchResult.addGeocodes(search.getGeocodes());
+ }
}
return searchResult;
@@ -139,7 +157,7 @@ public class GCBase {
* Retrieved data.
* @return SearchResult. Never null.
*/
- public static SearchResult parseMapJSON(final String data, Tile tile, Bitmap bitmap) {
+ public static SearchResult parseMapJSON(final String data, Tile tile, Bitmap bitmap, final Strategy strategy) {
final SearchResult searchResult = new SearchResult();
@@ -233,10 +251,14 @@ public class GCBase {
cache.setName(nameCache.get(id));
cache.setZoomlevel(tile.getZoomlevel());
cache.setCoords(tile.getCoord(xy));
- if (tile.getZoomlevel() >= 14) {
- parseMapPNG14(cache, bitmap, xy);
+ if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY)) {
+ if (tile.getZoomlevel() >= 14) {
+ parseMapPNG14(cache, bitmap, xy);
+ } else {
+ parseMapPNG13(cache, bitmap, xy);
+ }
} else {
- parseMapPNG13(cache, bitmap, xy);
+ cache.setType(CacheType.UNKNOWN);
}
searchResult.addCache(cache);
}
@@ -341,12 +363,14 @@ public class GCBase {
* @param viewport
* @return
*/
- protected static List<Tile> getTilesForViewport(final Viewport viewport) {
- List<Tile> tiles = new ArrayList<Tile>();
- if (!Settings.isPremiumMember()) {
- tiles.add(new Tile(viewport.getCenter(), 14)); // precise coords for caches nearby. searchByCoords() is used for PMs
- }
- tiles.add(new Tile(viewport.getCenter(), 12)); // other caches around
+ protected static Set<Tile> getTilesForViewport(final Viewport viewport) {
+ Set<Tile> tiles = new HashSet<Tile>();
+ int zoom = Math.min(Tile.calcZoomLon(viewport.bottomLeft, viewport.topRight),
+ Tile.calcZoomLat(viewport.bottomLeft, viewport.topRight));
+ tiles.add(new Tile(viewport.bottomLeft, zoom));
+ tiles.add(new Tile(new Geopoint(viewport.getLatitudeMin(), viewport.getLongitudeMax()), zoom));
+ tiles.add(new Tile(new Geopoint(viewport.getLatitudeMax(), viewport.getLongitudeMin()), zoom));
+ tiles.add(new Tile(viewport.topRight, zoom));
return tiles;
}
diff --git a/main/src/cgeo/geocaching/connector/gc/Tile.java b/main/src/cgeo/geocaching/connector/gc/Tile.java
index 7c78373..318b04f 100644
--- a/main/src/cgeo/geocaching/connector/gc/Tile.java
+++ b/main/src/cgeo/geocaching/connector/gc/Tile.java
@@ -38,7 +38,8 @@ public class Tile {
public Tile(Geopoint origin, int zoomlevel) {
assert zoomlevel >= ZOOMLEVEL_MIN && zoomlevel <= ZOOMLEVEL_MAX : "zoomlevel out of range";
- this.zoomlevel = zoomlevel;
+ this.zoomlevel = Math.max(Math.min(zoomlevel, ZOOMLEVEL_MAX), ZOOMLEVEL_MIN);
+ ;
tileX = calcX(origin);
tileY = calcY(origin);
}
@@ -106,4 +107,68 @@ public class Tile {
public String toString() {
return String.format("(%d/%d), zoom=%d", tileX, tileY, zoomlevel);
}
+
+ public static int calcZoomLon(final Geopoint left, final Geopoint right) {
+
+ int zoom = (int) Math.floor(
+ Math.log(360.0 / Math.abs(left.getLongitude() - right.getLongitude()))
+ / Math.log(2)
+ );
+
+ Tile tileLeft = new Tile(left, zoom);
+ Tile tileRight = new Tile(right, zoom);
+
+ if (tileLeft.getX() == tileRight.getX()) {
+ zoom = zoom + 1;
+ }
+
+ return Math.min(zoom, ZOOMLEVEL_MAX);
+ }
+
+ public static int calcZoomLat(final Geopoint bottom, final Geopoint top) {
+
+ int zoom = (int) Math.ceil(
+ Math.log(2 * Math.PI /
+ Math.abs(
+ asinh(tanGrad(bottom.getLatitude()))
+ - asinh(tanGrad(top.getLatitude()))
+ )
+ ) / Math.log(2)
+ );
+
+ Tile tileBottom = new Tile(bottom, zoom);
+ Tile tileTop = new Tile(top, zoom);
+
+ if (Math.abs(tileBottom.getX() - tileTop.getX()) > 1) {
+ zoom = zoom - 1;
+ }
+
+ return Math.min(zoom, ZOOMLEVEL_MAX);
+ }
+
+ private static double tanGrad(double angleGrad) {
+ return Math.tan(angleGrad / 180.0 * Math.PI);
+ }
+
+ private static double asinh(double x) {
+ return Math.log(x + Math.sqrt(x * x + 1.0));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Tile)) {
+ return false;
+ }
+ return (this.getX() == ((Tile) o).getX())
+ && (this.getY() == ((Tile) o).getY())
+ && (this.getZoomlevel() == ((Tile) o).getZoomlevel());
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
}
diff --git a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
new file mode 100644
index 0000000..834cdb8
--- /dev/null
+++ b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
@@ -0,0 +1,58 @@
+package cgeo.geocaching.enumerations;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgeoapplication;
+
+import java.util.EnumSet;
+
+/**
+ * Defines the strategy for the Live Map
+ *
+ * @author blafoo
+ *
+ */
+public class LiveMapStrategy {
+
+ public enum StrategyFlag {
+ LOAD_TILES, // 2x2 tiles filling the complete viewport
+ PARSE_TILES, // parse PNG images
+ SEARCH_NEARBY // searchByCoords()
+ }
+
+ public enum Strategy {
+ FASTEST(1, EnumSet.of(StrategyFlag.LOAD_TILES), R.string.map_strategy_fastest),
+ FAST(2, EnumSet.of(StrategyFlag.LOAD_TILES, StrategyFlag.PARSE_TILES), R.string.map_strategy_fast),
+ AUTO(3, EnumSet.noneOf(StrategyFlag.class), R.string.map_strategy_auto),
+ DETAILED(4, EnumSet.allOf(StrategyFlag.class), R.string.map_strategy_detailed);
+
+ public final int id;
+ public final EnumSet<StrategyFlag> flags;
+ private final int stringId;
+ private String l10n; // not final because the locale can be changed
+
+ Strategy(int id, EnumSet<StrategyFlag> flags, int stringId) {
+ this.id = id;
+ this.flags = flags;
+ this.stringId = stringId;
+ setL10n();
+ }
+
+ public final static Strategy getById(final int id) {
+ for (Strategy strategy : Strategy.values()) {
+ if (strategy.id == id) {
+ return strategy;
+ }
+ }
+ return AUTO;
+ }
+
+ public final String getL10n() {
+ return l10n;
+ }
+
+ public void setL10n() {
+ this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(this.stringId);
+ }
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index 0310dc3..2ce4c42 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -18,6 +18,7 @@ import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.gc.GCBase;
import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.enumerations.WaypointType;
@@ -93,8 +94,14 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
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 MENU_AS_LIST = 6;
+ private static final int SUBMENU_STRATEGY = 5;
+ private static final int MENU_STRATEGY_FASTEST = 51;
+ private static final int MENU_STRATEGY_FAST = 52;
+ private static final int MENU_STRATEGY_AUTO = 53;
+ private static final int MENU_STRATEGY_DETAILED = 74;
+
+ private static final int MENU_CIRCLE_MODE = 6;
+ private static final int MENU_AS_LIST = 7;
private static final String EXTRAS_MAP_TITLE = "mapTitle";
@@ -548,6 +555,16 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
menu.add(0, MENU_MAP_LIVE, 0, res.getString(R.string.map_live_disable)).setIcon(R.drawable.ic_menu_refresh);
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(R.drawable.ic_menu_trail);
+
+ Strategy strategy = Settings.getLiveMapStrategy();
+ SubMenu subMenuStrategy = menu.addSubMenu(0, SUBMENU_STRATEGY, 0, res.getString(R.string.map_strategy));
+ subMenuStrategy.setHeaderTitle("Live Map strategy");
+ subMenuStrategy.add(2, MENU_STRATEGY_FASTEST, 0, Strategy.FASTEST.getL10n()).setCheckable(true).setChecked(strategy == Strategy.FASTEST);
+ subMenuStrategy.add(2, MENU_STRATEGY_FAST, 0, Strategy.FAST.getL10n()).setCheckable(true).setChecked(strategy == Strategy.FAST);
+ subMenuStrategy.add(2, MENU_STRATEGY_AUTO, 0, Strategy.AUTO.getL10n()).setCheckable(true).setChecked(strategy == Strategy.AUTO);
+ subMenuStrategy.add(2, MENU_STRATEGY_DETAILED, 0, Strategy.DETAILED.getL10n()).setCheckable(true).setChecked(strategy == Strategy.DETAILED);
+ subMenuStrategy.setGroupCheckable(2, true, true);
+
menu.add(0, MENU_CIRCLE_MODE, 0, res.getString(R.string.map_circles_hide)).setIcon(R.drawable.ic_menu_circle);
menu.add(0, MENU_AS_LIST, 0, res.getString(R.string.map_as_list)).setIcon(android.R.drawable.ic_menu_agenda);
@@ -595,6 +612,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
item = menu.findItem(MENU_AS_LIST);
item.setEnabled(live && CollectionUtils.isNotEmpty(caches));
+
} catch (Exception e) {
Log.e(Settings.tag, "cgeomap.onPrepareOptionsMenu: " + e.toString());
}
@@ -712,6 +730,26 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto
cgeocaches.startActivityMap(activity, search);
return true;
}
+ case MENU_STRATEGY_FASTEST: {
+ item.setChecked(true);
+ Settings.setLiveMapStrategy(Strategy.FASTEST);
+ return true;
+ }
+ case MENU_STRATEGY_FAST: {
+ item.setChecked(true);
+ Settings.setLiveMapStrategy(Strategy.FAST);
+ return true;
+ }
+ case MENU_STRATEGY_AUTO: {
+ item.setChecked(true);
+ Settings.setLiveMapStrategy(Strategy.AUTO);
+ return true;
+ }
+ case MENU_STRATEGY_DETAILED: {
+ item.setChecked(true);
+ Settings.setLiveMapStrategy(Strategy.DETAILED);
+ return true;
+ }
default:
if (MapProviderFactory.isValidSourceId(MapProviderFactory.getMapSourceFromMenuId(id))) {
item.setChecked(true);