diff options
| author | blafoo <github@blafoo.de> | 2012-03-07 23:12:55 +0100 |
|---|---|---|
| committer | blafoo <github@blafoo.de> | 2012-03-07 23:12:55 +0100 |
| commit | d6477fcae75ce1de889246b7fb789c56aa25cc56 (patch) | |
| tree | 12cbcde5b4da48fef337e807761507b74682e130 /main/src/cgeo | |
| parent | 734d52565d401abb9701f5e5efbb278745021e03 (diff) | |
| download | cgeo-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.java | 17 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgeo.java | 9 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgeoapplication.java | 4 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/GCBase.java | 62 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/Tile.java | 67 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java | 58 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/maps/CGeoMap.java | 42 |
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); |
