diff options
Diffstat (limited to 'main/src/cgeo/geocaching/maps/CGeoMap.java')
-rw-r--r-- | main/src/cgeo/geocaching/maps/CGeoMap.java | 464 |
1 files changed, 279 insertions, 185 deletions
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java index 9bbf7af..42e41b1 100644 --- a/main/src/cgeo/geocaching/maps/CGeoMap.java +++ b/main/src/cgeo/geocaching/maps/CGeoMap.java @@ -4,8 +4,10 @@ import butterknife.ButterKnife; import cgeo.geocaching.CacheListActivity; import cgeo.geocaching.CgeoApplication; +import cgeo.geocaching.CompassActivity; import cgeo.geocaching.DataStore; import cgeo.geocaching.Geocache; +import cgeo.geocaching.Intents; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Waypoint; @@ -15,13 +17,12 @@ import cgeo.geocaching.connector.gc.GCLogin; import cgeo.geocaching.connector.gc.MapTokens; import cgeo.geocaching.connector.gc.Tile; import cgeo.geocaching.enumerations.CacheType; -import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; import cgeo.geocaching.enumerations.WaypointType; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.list.StoredList; +import cgeo.geocaching.location.Geopoint; +import cgeo.geocaching.location.Viewport; import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl; import cgeo.geocaching.maps.interfaces.GeoPointImpl; import cgeo.geocaching.maps.interfaces.MapActivityImpl; @@ -31,13 +32,15 @@ import cgeo.geocaching.maps.interfaces.MapProvider; import cgeo.geocaching.maps.interfaces.MapSource; import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OnMapDragListener; -import cgeo.geocaching.sensors.DirectionProvider; +import cgeo.geocaching.network.AndroidBeam; +import cgeo.geocaching.sensors.GeoData; import cgeo.geocaching.sensors.GeoDirHandler; -import cgeo.geocaching.sensors.IGeoData; +import cgeo.geocaching.sensors.Sensors; import cgeo.geocaching.settings.Settings; import cgeo.geocaching.ui.dialog.LiveMapInfoDialogBuilder; import cgeo.geocaching.utils.AngleUtils; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Formatter; import cgeo.geocaching.utils.LeastRecentlyUsedSet; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.MapUtils; @@ -45,6 +48,7 @@ import cgeo.geocaching.utils.MapUtils; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import rx.Subscription; import rx.functions.Action0; @@ -61,11 +65,13 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.location.Location; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; @@ -123,16 +129,6 @@ public class CGeoMap extends AbstractMap implements ViewFactory { private static final int UPDATE_PROGRESS = 0; private static final int FINISHED_LOADING_DETAILS = 1; - //Menu - private static final String EXTRAS_GEOCODE = "geocode"; - private static final String EXTRAS_COORDS = "coords"; - private static final String EXTRAS_WPTTYPE = "wpttype"; - private static final String EXTRAS_MAPSTATE = "mapstate"; - private static final String EXTRAS_SEARCH = "search"; - private static final String EXTRAS_MAP_TITLE = "mapTitle"; - private static final String EXTRAS_MAP_MODE = "mapMode"; - private static final String EXTRAS_LIVE_ENABLED = "liveEnabled"; - private static final String BUNDLE_MAP_SOURCE = "mapSource"; private static final String BUNDLE_MAP_STATE = "mapState"; private static final String BUNDLE_LIVE_ENABLED = "liveEnabled"; @@ -141,15 +137,14 @@ public class CGeoMap extends AbstractMap implements ViewFactory { // Those are initialized in onCreate() and will never be null afterwards private Resources res; private Activity activity; - private CgeoApplication app; private MapItemFactory mapItemFactory; private String mapTitle; - private LeastRecentlyUsedSet<Geocache> caches; + final private LeastRecentlyUsedSet<Geocache> caches = new LeastRecentlyUsedSet<>(MAX_CACHES + DataStore.getAllCachesCount()); private MapViewImpl mapView; private CachesOverlay overlayCaches; private PositionAndScaleOverlay overlayPositionAndScale; - final private GeoDirHandler geoDirUpdate; + final private GeoDirHandler geoDirUpdate = new UpdateLoc(this); private SearchResult searchIntent = null; private String geocodeIntent = null; private Geopoint coordsIntent = null; @@ -161,7 +156,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { private MapTokens tokens = null; private boolean noMapTokenShowed = false; // map status data - private boolean followMyLocation = false; + private static boolean followMyLocation = true; // threads private Subscription loadTimer; private LoadDetails loadDetailsThread = null; @@ -191,19 +186,20 @@ public class CGeoMap extends AbstractMap implements ViewFactory { private boolean centered = false; // if map is already centered private boolean alreadyCentered = false; // -""- for setting my location private static final Set<String> dirtyCaches = new HashSet<>(); + // flag for honeycomb special popup menu handling + private boolean honeycombMenu = false; /** * if live map is enabled, this is the minimum zoom level, independent of the stored setting */ private static final int MIN_LIVEMAP_ZOOM = 12; // Thread pooling - private static BlockingQueue<Runnable> displayQueue = new ArrayBlockingQueue<>(1); - private static ThreadPoolExecutor displayExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, displayQueue, new ThreadPoolExecutor.DiscardOldestPolicy()); - private static BlockingQueue<Runnable> downloadQueue = new ArrayBlockingQueue<>(1); - private static ThreadPoolExecutor downloadExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, downloadQueue, new ThreadPoolExecutor.DiscardOldestPolicy()); - private static BlockingQueue<Runnable> loadQueue = new ArrayBlockingQueue<>(1); - - private static ThreadPoolExecutor loadExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, loadQueue, new ThreadPoolExecutor.DiscardOldestPolicy()); + private static final BlockingQueue<Runnable> displayQueue = new ArrayBlockingQueue<>(1); + private static final ThreadPoolExecutor displayExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, displayQueue, new ThreadPoolExecutor.DiscardOldestPolicy()); + private static final BlockingQueue<Runnable> downloadQueue = new ArrayBlockingQueue<>(1); + private static final ThreadPoolExecutor downloadExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, downloadQueue, new ThreadPoolExecutor.DiscardOldestPolicy()); + private static final BlockingQueue<Runnable> loadQueue = new ArrayBlockingQueue<>(1); + private static final ThreadPoolExecutor loadExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, loadQueue, new ThreadPoolExecutor.DiscardOldestPolicy()); // handlers /** Updates the titles */ @@ -224,29 +220,9 @@ public class CGeoMap extends AbstractMap implements ViewFactory { switch (what) { case UPDATE_TITLE: - // set title - final StringBuilder title = new StringBuilder(); - - if (map.mapMode == MapMode.LIVE && map.isLiveEnabled) { - title.append(map.res.getString(R.string.map_live)); - } else { - title.append(map.mapTitle); - } - - map.countVisibleCaches(); - if (!map.caches.isEmpty() && !map.mapTitle.contains("[")) { - title.append(" [").append(map.cachesCnt); - if (map.cachesCnt != map.caches.size()) { - title.append('/').append(map.caches.size()); - } - title.append(']'); - } + map.setTitle(); + map.setSubtitle(); - if (Settings.isDebug() && map.lastSearchResult != null && StringUtils.isNotBlank(map.lastSearchResult.getUrl())) { - title.append('[').append(map.lastSearchResult.getUrl()).append(']'); - } - - map.setTitle(title.toString()); break; case INVALIDATE_MAP: map.mapView.repaintRequired(null); @@ -261,7 +237,8 @@ public class CGeoMap extends AbstractMap implements ViewFactory { final private Handler displayHandler = new DisplayHandler(this); - private void setTitle(final String title) { + private void setTitle() { + final String title = calculateTitle(); /* Compatibility for the old Action Bar, only used by the maps activity at the moment */ final TextView titleview = ButterKnife.findById(activity, R.id.actionbar_title); if (titleview != null) { @@ -273,10 +250,84 @@ public class CGeoMap extends AbstractMap implements ViewFactory { } } + private String calculateTitle() { + if (isLiveEnabled) { + return res.getString(R.string.map_live); + } + if (mapMode == MapMode.SINGLE) { + final Geocache cache = getSingleModeCache(); + if (cache != null) { + return cache.getName(); + } + } + return StringUtils.defaultIfEmpty(mapTitle, res.getString(R.string.map_map)); + } + + @Nullable + private Geocache getSingleModeCache() { + // use a copy of the caches list to avoid concurrent modification + for (final Geocache geocache : new ArrayList<>(caches)) { + if (geocache.getGeocode().equals(geocodeIntent)) { + return geocache; + } + } + return null; + } + + private void setSubtitle() { + final String subtitle = calculateSubtitle(); + if (StringUtils.isEmpty(subtitle)) { + return; + } + + /* Compatibility for the old Action Bar, only used by the maps activity at the moment */ + final TextView titleView = ButterKnife.findById(activity, R.id.actionbar_title); + if (titleView != null) { + titleView.setText(titleView.getText().toString() + ' ' + subtitle); + } + if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)) { + setSubtitleIceCreamSandwich(subtitle); + } + } + + private String calculateSubtitle() { + // count caches in the sub title + countVisibleCaches(); + final StringBuilder subtitle = new StringBuilder(); + if (!isLiveEnabled && mapMode == MapMode.SINGLE) { + final Geocache cache = getSingleModeCache(); + if (cache != null) { + return Formatter.formatMapSubtitle(cache); + } + } + if (!caches.isEmpty()) { + final int totalCount = caches.size(); + + if (cachesCnt != totalCount && Settings.isDebug()) { + subtitle.append(cachesCnt).append('/').append(res.getQuantityString(R.plurals.cache_counts, totalCount, totalCount)); + } + else { + subtitle.append(res.getQuantityString(R.plurals.cache_counts, cachesCnt, cachesCnt)); + } + } + + if (Settings.isDebug() && lastSearchResult != null && StringUtils.isNotBlank(lastSearchResult.getUrl())) { + subtitle.append(" [").append(lastSearchResult.getUrl()).append(']'); + } + + return subtitle.toString(); + } + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private void setTitleIceCreamSandwich(final String title) { activity.getActionBar().setTitle(title); } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + private void setSubtitleIceCreamSandwich(final String subtitle) { + activity.getActionBar().setSubtitle(subtitle); + } + /** Updates the progress. */ private static final class ShowProgressHandler extends Handler { private int counter = 0; @@ -331,7 +382,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { if (msg.what == UPDATE_PROGRESS) { if (waitDialog != null) { final int secondsElapsed = (int) ((System.currentTimeMillis() - detailProgressTime) / 1000); - int secondsRemaining; + final int secondsRemaining; if (detailProgress > 0) { secondsRemaining = (detailTotal - detailProgress) * secondsElapsed / detailProgress; } else { @@ -367,25 +418,10 @@ public class CGeoMap extends AbstractMap implements ViewFactory { public CGeoMap(final MapActivityImpl activity) { super(activity); - geoDirUpdate = new UpdateLoc(this); } protected void countVisibleCaches() { - final List<Geocache> protectedCaches = caches.getAsList(); - - int count = 0; - if (!protectedCaches.isEmpty()) { - final Viewport viewport = mapView.getViewport(); - - for (final Geocache cache : protectedCaches) { - if (cache != null && cache.getCoords() != null) { - if (viewport.contains(cache)) { - count++; - } - } - } - } - cachesCnt = count; + cachesCnt = mapView.getViewport().count(caches.getAsList()); } @Override @@ -404,10 +440,6 @@ public class CGeoMap extends AbstractMap implements ViewFactory { // class init res = this.getResources(); activity = this.getActivity(); - app = (CgeoApplication) activity.getApplication(); - - final int countBubbleCnt = DataStore.getAllCachesCount(); - caches = new LeastRecentlyUsedSet<>(MAX_CACHES + countBubbleCnt); final MapProvider mapProvider = Settings.getMapProvider(); mapItemFactory = mapProvider.getMapItemFactory(); @@ -415,14 +447,14 @@ public class CGeoMap extends AbstractMap implements ViewFactory { // Get parameters from the intent final Bundle extras = activity.getIntent().getExtras(); if (extras != null) { - mapMode = (MapMode) extras.get(EXTRAS_MAP_MODE); - isLiveEnabled = extras.getBoolean(EXTRAS_LIVE_ENABLED, false); - searchIntent = extras.getParcelable(EXTRAS_SEARCH); - geocodeIntent = extras.getString(EXTRAS_GEOCODE); - coordsIntent = extras.getParcelable(EXTRAS_COORDS); - waypointTypeIntent = WaypointType.findById(extras.getString(EXTRAS_WPTTYPE)); - mapStateIntent = extras.getIntArray(EXTRAS_MAPSTATE); - mapTitle = extras.getString(EXTRAS_MAP_TITLE); + mapMode = (MapMode) extras.get(Intents.EXTRA_MAP_MODE); + isLiveEnabled = extras.getBoolean(Intents.EXTRA_LIVE_ENABLED, false); + searchIntent = extras.getParcelable(Intents.EXTRA_SEARCH); + geocodeIntent = extras.getString(Intents.EXTRA_GEOCODE); + coordsIntent = extras.getParcelable(Intents.EXTRA_COORDS); + waypointTypeIntent = WaypointType.findById(extras.getString(Intents.EXTRA_WPTTYPE)); + mapStateIntent = extras.getIntArray(Intents.EXTRA_MAPSTATE); + mapTitle = extras.getString(Intents.EXTRA_TITLE); } else { mapMode = MapMode.LIVE; @@ -461,7 +493,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { activity.getActionBar().setDisplayHomeAsUpEnabled(true); } activity.setContentView(mapProvider.getMapLayoutId()); - setTitle(res.getString(R.string.map_map)); + setTitle(); // initialize map mapView = (MapViewImpl) activity.findViewById(mapProvider.getMapViewId()); @@ -475,18 +507,21 @@ public class CGeoMap extends AbstractMap implements ViewFactory { mapView.clearOverlays(); overlayCaches = mapView.createAddMapOverlay(mapView.getContext(), getResources().getDrawable(R.drawable.marker)); - overlayPositionAndScale = mapView.createAddPositionAndScaleOverlay(); + + + overlayPositionAndScale = mapView.createAddPositionAndScaleOverlay(coordsIntent, geocodeIntent); if (trailHistory != null) { overlayPositionAndScale.setHistory(trailHistory); } + mapView.repaintRequired(null); - setZoom(Settings.getMapZoom()); + setZoom(Settings.getMapZoom(mapMode)); mapView.getMapController().setCenter(Settings.getMapCenter()); if (null == mapStateIntent) { - followMyLocation = mapMode == MapMode.LIVE; + followMyLocation = followMyLocation && (mapMode == MapMode.LIVE); } else { followMyLocation = 1 == mapStateIntent[3]; if ((overlayCaches.getCircles() ? 1 : 0) != mapStateIntent[4]) { @@ -504,9 +539,22 @@ public class CGeoMap extends AbstractMap implements ViewFactory { } prepareFilterBar(); - if (!app.isLiveMapHintShownInThisSession() && !Settings.getHideLiveMapHint() && Settings.getLiveMapHintShowCount() <= 3) { + // Check for Honeycomb fake overflow button and attach popup + final View overflowActionBar = ButterKnife.findById(activity, R.id.overflowActionBar); + if (overflowActionBar != null) { + honeycombMenu = true; + overflowActionBar.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(final View v) { + showPopupHoneycomb(v); + } + }); + } + + if (!CgeoApplication.getInstance().isLiveMapHintShownInThisSession() && Settings.getLiveMapHintShowCount() <= 3) { LiveMapInfoDialogBuilder.create(activity).show(); } + AndroidBeam.disable(activity); } private void initMyLocationSwitchButton(final CheckBox locSwitch) { @@ -522,7 +570,6 @@ public class CGeoMap extends AbstractMap implements ViewFactory { /** * Set the zoom of the map. The zoom is restricted to a certain minimum in case of live map. * - * @param zoom */ private void setZoom(final int zoom) { mapView.getMapController().setZoom(isLiveEnabled ? Math.max(zoom, MIN_LIVEMAP_ZOOM) : zoom); @@ -546,18 +593,28 @@ public class CGeoMap extends AbstractMap implements ViewFactory { resumeSubscription = Subscriptions.from(geoDirUpdate.start(GeoDirHandler.UPDATE_GEODIR), startTimer()); if (!CollectionUtils.isEmpty(dirtyCaches)) { - for (final String geocode : dirtyCaches) { - final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); - if (cache != null) { - // new collection type needs to remove first - caches.remove(cache); - // re-add to update the freshness - caches.add(cache); + new AsyncTask<Void, Void, Void>() { + @Override + public Void doInBackground(final Void... params) { + for (final String geocode : dirtyCaches) { + final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); + if (cache != null) { + // new collection type needs to remove first + caches.remove(cache); + // re-add to update the freshness + caches.add(cache); + } + } + return null; } - } - dirtyCaches.clear(); - // Update display - displayExecutor.execute(new DisplayRunnable(this)); + + @Override + public void onPostExecute(final Void result) { + dirtyCaches.clear(); + // Update display + displayExecutor.execute(new DisplayRunnable(CGeoMap.this)); + } + }.execute(); } } @@ -581,10 +638,37 @@ public class CGeoMap extends AbstractMap implements ViewFactory { } @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void showPopupHoneycomb(final View view) { + // Inflate the core menu ourselves + final android.widget.PopupMenu popupMenu = new android.widget.PopupMenu(getActivity(), view); + final MenuInflater inflater = new MenuInflater(getActivity()); + inflater.inflate(R.menu.map_activity, popupMenu.getMenu()); + + // continue processing menu items as usual + onCreateOptionsMenu(popupMenu.getMenu()); + + onPrepareOptionsMenu(popupMenu.getMenu()); + + popupMenu.setOnMenuItemClickListener( + new android.widget.PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(final MenuItem item) { + return onOptionsItemSelected(item); + } + } + ); + // display menu + popupMenu.show(); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public boolean onCreateOptionsMenu(final Menu menu) { // menu inflation happens in Google/Mapsforge specific classes - super.onCreateOptionsMenu(menu); + // skip it for honeycomb - handled specially in @see showPopupHoneycomb + if (!honeycombMenu) { + super.onCreateOptionsMenu(menu); + } MapProviderFactory.addMapviewMenuItems(menu); @@ -592,7 +676,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { subMenuStrategy.setHeaderTitle(res.getString(R.string.map_strategy_title)); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { /* if we have an Actionbar find the my position toggle */ final MenuItem item = menu.findItem(R.id.menu_toggle_mypos); myLocSwitch = new CheckBox(activity); @@ -640,7 +724,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { item = menu.findItem(R.id.menu_theme_mode); // show theme selection item.setVisible(mapView.hasMapThemes()); - menu.findItem(R.id.menu_as_list).setVisible(!isLoading()); + menu.findItem(R.id.menu_as_list).setVisible(!isLoading() && caches.size() > 1); menu.findItem(R.id.submenu_strategy).setVisible(isLiveEnabled); @@ -657,6 +741,8 @@ public class CGeoMap extends AbstractMap implements ViewFactory { default: // DETAILED menu.findItem(R.id.menu_strategy_detailed).setChecked(true); } + menu.findItem(R.id.menu_hint).setVisible(mapMode == MapMode.SINGLE); + menu.findItem(R.id.menu_compass).setVisible(mapMode == MapMode.SINGLE); } catch (final RuntimeException e) { Log.e("CGeoMap.onPrepareOptionsMenu", e); } @@ -685,6 +771,10 @@ public class CGeoMap extends AbstractMap implements ViewFactory { lastSearchResult = null; searchIntent = null; ActivityMixin.invalidateOptionsMenu(activity); + if (mapMode != MapMode.SINGLE) { + mapTitle = StringUtils.EMPTY; + } + updateMapTitle(); return true; case R.id.menu_store_caches: if (!isLoading()) { @@ -714,7 +804,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { public void call(final Integer selectedListId) { storeCaches(geocodes, selectedListId); } - }, true, StoredList.TEMPORARY_LIST_ID); + }, true, StoredList.TEMPORARY_LIST.id); } else { storeCaches(geocodes, StoredList.STANDARD_LIST_ID); } @@ -742,24 +832,30 @@ public class CGeoMap extends AbstractMap implements ViewFactory { } case R.id.menu_strategy_fastest: { item.setChecked(true); - Settings.setLiveMapStrategy(Strategy.FASTEST); + Settings.setLiveMapStrategy(LivemapStrategy.FASTEST); return true; } case R.id.menu_strategy_fast: { item.setChecked(true); - Settings.setLiveMapStrategy(Strategy.FAST); + Settings.setLiveMapStrategy(LivemapStrategy.FAST); return true; } case R.id.menu_strategy_auto: { item.setChecked(true); - Settings.setLiveMapStrategy(Strategy.AUTO); + Settings.setLiveMapStrategy(LivemapStrategy.AUTO); return true; } case R.id.menu_strategy_detailed: { item.setChecked(true); - Settings.setLiveMapStrategy(Strategy.DETAILED); + Settings.setLiveMapStrategy(LivemapStrategy.DETAILED); return true; } + case R.id.menu_hint: + menuShowHint(); + return true; + case R.id.menu_compass: + menuCompass(); + return true; default: final MapSource mapSource = MapProviderFactory.getMapSource(id); if (mapSource != null) { @@ -771,6 +867,20 @@ public class CGeoMap extends AbstractMap implements ViewFactory { return false; } + private void menuCompass() { + final Geocache cache = getSingleModeCache(); + if (cache != null) { + CompassActivity.startActivityCache(this.getActivity(), cache); + } + } + + private void menuShowHint() { + final Geocache cache = getSingleModeCache(); + if (cache != null) { + cache.showHintToast(getActivity()); + } + } + private void selectMapTheme() { final File[] themeFiles = Settings.getMapThemeFiles(); @@ -853,7 +963,12 @@ public class CGeoMap extends AbstractMap implements ViewFactory { if (restartRequired) { mapRestart(); } else if (mapView != null) { // changeMapSource can be called by onCreate() + mapStateIntent = currentMapState(); mapView.setMapSource(); + // re-center the map + centered = false; + centerMap(geocodeIntent, searchIntent, coordsIntent, mapStateIntent); + // re-build menues ActivityMixin.invalidateOptionsMenu(activity); } @@ -864,27 +979,27 @@ public class CGeoMap extends AbstractMap implements ViewFactory { * Restart the current activity with the default map source. */ private void mapRestart() { - // close old mapview - activity.finish(); - // prepare information to restart a similar view final Intent mapIntent = new Intent(activity, Settings.getMapProvider().getMapClass()); - mapIntent.putExtra(EXTRAS_SEARCH, searchIntent); - mapIntent.putExtra(EXTRAS_GEOCODE, geocodeIntent); + mapIntent.putExtra(Intents.EXTRA_SEARCH, searchIntent); + mapIntent.putExtra(Intents.EXTRA_GEOCODE, geocodeIntent); if (coordsIntent != null) { - mapIntent.putExtra(EXTRAS_COORDS, coordsIntent); + mapIntent.putExtra(Intents.EXTRA_COORDS, coordsIntent); } - mapIntent.putExtra(EXTRAS_WPTTYPE, waypointTypeIntent != null ? waypointTypeIntent.id : null); - mapIntent.putExtra(EXTRAS_MAP_TITLE, mapTitle); - mapIntent.putExtra(EXTRAS_MAP_MODE, mapMode); - mapIntent.putExtra(EXTRAS_LIVE_ENABLED, isLiveEnabled); + mapIntent.putExtra(Intents.EXTRA_WPTTYPE, waypointTypeIntent != null ? waypointTypeIntent.id : null); + mapIntent.putExtra(Intents.EXTRA_TITLE, mapTitle); + mapIntent.putExtra(Intents.EXTRA_MAP_MODE, mapMode); + mapIntent.putExtra(Intents.EXTRA_LIVE_ENABLED, isLiveEnabled); final int[] mapState = currentMapState(); if (mapState != null) { - mapIntent.putExtra(EXTRAS_MAPSTATE, mapState); + mapIntent.putExtra(Intents.EXTRA_MAPSTATE, mapState); } + // close old map + activity.finish(); + // start the new map activity.startActivity(mapIntent); } @@ -909,13 +1024,13 @@ public class CGeoMap extends AbstractMap implements ViewFactory { } private void savePrefs() { - Settings.setMapZoom(mapView.getMapZoomLevel()); + Settings.setMapZoom(mapMode, mapView.getMapZoomLevel()); Settings.setMapCenter(mapView.getMapViewCenter()); } // Set center of map to my location if appropriate. - private void myLocationInMiddle(final IGeoData geo) { - if (followMyLocation && !geo.isPseudoLocation()) { + private void myLocationInMiddle(final GeoData geo) { + if (followMyLocation) { centerMap(geo.getCoords()); } } @@ -931,8 +1046,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { // minimum change of location in fraction of map width/height (whatever is smaller) for position overlay update private static final float MIN_LOCATION_DELTA = 0.01f; - Location currentLocation = new Location(""); - boolean locationValid = false; + Location currentLocation = Sensors.getInstance().currentGeo(); float currentHeading; private long timeLastPositionOverlayCalculation = 0; @@ -946,16 +1060,10 @@ public class CGeoMap extends AbstractMap implements ViewFactory { } @Override - public void updateGeoDir(final IGeoData geo, final float dir) { - if (geo.isPseudoLocation()) { - locationValid = false; - } else { - locationValid = true; - - currentLocation = geo.getLocation(); - currentHeading = DirectionProvider.getDirectionNow(dir); - repaintPositionOverlay(); - } + public void updateGeoDir(final GeoData geo, final float dir) { + currentLocation = geo; + currentHeading = AngleUtils.getDirectionNow(dir); + repaintPositionOverlay(); } /** @@ -969,23 +1077,24 @@ public class CGeoMap extends AbstractMap implements ViewFactory { try { final CGeoMap map = mapRef.get(); if (map != null) { - final boolean needsRepaintForDistance = needsRepaintForDistance(); + final boolean needsRepaintForDistanceOrAccuracy = needsRepaintForDistanceOrAccuracy(); final boolean needsRepaintForHeading = needsRepaintForHeading(); - if (needsRepaintForDistance) { - if (map.followMyLocation) { + if (needsRepaintForDistanceOrAccuracy) { + if (CGeoMap.followMyLocation) { map.centerMap(new Geopoint(currentLocation)); } } - if (needsRepaintForDistance || needsRepaintForHeading) { + if (needsRepaintForDistanceOrAccuracy || needsRepaintForHeading) { + map.overlayPositionAndScale.setCoordinates(currentLocation); map.overlayPositionAndScale.setHeading(currentHeading); map.mapView.repaintRequired(map.overlayPositionAndScale); } } } catch (final RuntimeException e) { - Log.w("Failed to update location."); + Log.w("Failed to update location", e); } } } @@ -998,11 +1107,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { return Math.abs(AngleUtils.difference(currentHeading, map.overlayPositionAndScale.getHeading())) > MIN_HEADING_DELTA; } - boolean needsRepaintForDistance() { - if (!locationValid) { - return false; - } - + boolean needsRepaintForDistanceOrAccuracy() { final CGeoMap map = mapRef.get(); if (map == null) { return false; @@ -1011,6 +1116,9 @@ public class CGeoMap extends AbstractMap implements ViewFactory { float dist = Float.MAX_VALUE; if (lastLocation != null) { + if (lastLocation.getAccuracy() != currentLocation.getAccuracy()) { + return true; + } dist = currentLocation.distanceTo(lastLocation); } @@ -1028,7 +1136,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { } /** - * Starts the {@link LoadTimer}. + * Starts the load timer. */ private Subscription startTimer() { @@ -1037,7 +1145,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { displayPoint(coordsIntent); loadTimer = Subscriptions.empty(); } else { - loadTimer = startLoadTimer(); + loadTimer = Schedulers.newThread().createWorker().schedulePeriodically(new LoadTimerAction(this), 0, 250, TimeUnit.MILLISECONDS); } return loadTimer; } @@ -1072,7 +1180,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { // update title on any change if (moved || !viewportNow.equals(previousViewport)) { - map.displayHandler.sendEmptyMessage(UPDATE_TITLE); + map.updateMapTitle(); } previousZoom = zoomNow; @@ -1094,16 +1202,8 @@ public class CGeoMap extends AbstractMap implements ViewFactory { } /** - * loading timer Triggers every 250ms and checks for viewport change and starts a {@link LoadRunnable}. - */ - private Subscription startLoadTimer() { - return Schedulers.newThread().createWorker().schedulePeriodically(new LoadTimerAction(this), 0, 250, TimeUnit.MILLISECONDS); - } - - /** * get if map is loading something * - * @return */ public boolean isLoading() { return !loadTimer.isUnsubscribed() && @@ -1114,7 +1214,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { /** * Worker thread that loads caches and waypoints from the database and then spawns the {@link DownloadRunnable}. - * started by {@link LoadTimer} + * started by the load timer. */ private static class LoadRunnable extends DoRunnable { @@ -1134,7 +1234,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { showProgressHandler.sendEmptyMessage(SHOW_PROGRESS); loadThreadRun = System.currentTimeMillis(); - SearchResult searchResult; + final SearchResult searchResult; if (mapMode == MapMode.LIVE) { searchResult = isLiveEnabled ? new SearchResult() : new SearchResult(DataStore.loadStoredInViewport(mapView.getViewport(), Settings.getCacheType())); } else { @@ -1250,9 +1350,6 @@ public class CGeoMap extends AbstractMap implements ViewFactory { //render displayExecutor.execute(new DisplayRunnable(this)); - } catch (final ThreadDeath e) { - Log.d("DownloadThread stopped"); - displayHandler.sendEmptyMessage(UPDATE_TITLE); } finally { showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); // hide progress } @@ -1302,19 +1399,14 @@ public class CGeoMap extends AbstractMap implements ViewFactory { } itemsToDisplay.add(getCacheItem(cache)); } - - overlayCaches.updateItems(itemsToDisplay); - displayHandler.sendEmptyMessage(INVALIDATE_MAP); - - } else { + } + // don't add other waypoints to overlayCaches if just one point should be displayed + if (coordsIntent == null) { overlayCaches.updateItems(itemsToDisplay); - displayHandler.sendEmptyMessage(INVALIDATE_MAP); } + displayHandler.sendEmptyMessage(INVALIDATE_MAP); - displayHandler.sendEmptyMessage(UPDATE_TITLE); - } catch (final ThreadDeath e) { - Log.d("DisplayThread stopped"); - displayHandler.sendEmptyMessage(UPDATE_TITLE); + updateMapTitle(); } finally { showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); } @@ -1327,11 +1419,15 @@ public class CGeoMap extends AbstractMap implements ViewFactory { final CachesOverlayItemImpl item = getWaypointItem(waypoint); overlayCaches.updateItems(item); displayHandler.sendEmptyMessage(INVALIDATE_MAP); - displayHandler.sendEmptyMessage(UPDATE_TITLE); + updateMapTitle(); cachesCnt = 1; } + private void updateMapTitle() { + displayHandler.sendEmptyMessage(UPDATE_TITLE); + } + private static abstract class DoRunnable implements Runnable { private final WeakReference<CGeoMap> mapRef; @@ -1538,7 +1634,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory { if (myLocSwitch != null) { myLocSwitch.setChecked(followMyLocation); if (followMyLocation) { - myLocationInMiddle(app.currentGeo()); + myLocationInMiddle(Sensors.getInstance().currentGeo()); } } } @@ -1610,42 +1706,40 @@ public class CGeoMap extends AbstractMap implements ViewFactory { public static void startActivitySearch(final Activity fromActivity, final SearchResult search, final String title) { final Intent mapIntent = newIntent(fromActivity); - mapIntent.putExtra(EXTRAS_SEARCH, search); - mapIntent.putExtra(EXTRAS_MAP_MODE, MapMode.LIST); - mapIntent.putExtra(EXTRAS_LIVE_ENABLED, false); + mapIntent.putExtra(Intents.EXTRA_SEARCH, search); + mapIntent.putExtra(Intents.EXTRA_MAP_MODE, MapMode.LIST); + mapIntent.putExtra(Intents.EXTRA_LIVE_ENABLED, false); if (StringUtils.isNotBlank(title)) { - mapIntent.putExtra(CGeoMap.EXTRAS_MAP_TITLE, title); + mapIntent.putExtra(Intents.EXTRA_TITLE, title); } fromActivity.startActivity(mapIntent); } - public static void startActivityLiveMap(final Activity fromActivity) { - final Intent mapIntent = newIntent(fromActivity); - mapIntent.putExtra(EXTRAS_MAP_MODE, MapMode.LIVE); - mapIntent.putExtra(EXTRAS_LIVE_ENABLED, Settings.isLiveMap()); - fromActivity.startActivity(mapIntent); + public static Intent getLiveMapIntent(final Activity fromActivity) { + return newIntent(fromActivity) + .putExtra(Intents.EXTRA_MAP_MODE, MapMode.LIVE) + .putExtra(Intents.EXTRA_LIVE_ENABLED, Settings.isLiveMap()); } public static void startActivityCoords(final Activity fromActivity, final Geopoint coords, final WaypointType type, final String title) { final Intent mapIntent = newIntent(fromActivity); - mapIntent.putExtra(EXTRAS_MAP_MODE, MapMode.COORDS); - mapIntent.putExtra(EXTRAS_LIVE_ENABLED, false); - mapIntent.putExtra(EXTRAS_COORDS, coords); + mapIntent.putExtra(Intents.EXTRA_MAP_MODE, MapMode.COORDS); + mapIntent.putExtra(Intents.EXTRA_LIVE_ENABLED, false); + mapIntent.putExtra(Intents.EXTRA_COORDS, coords); if (type != null) { - mapIntent.putExtra(EXTRAS_WPTTYPE, type.id); + mapIntent.putExtra(Intents.EXTRA_WPTTYPE, type.id); } if (StringUtils.isNotBlank(title)) { - mapIntent.putExtra(EXTRAS_MAP_TITLE, title); + mapIntent.putExtra(Intents.EXTRA_TITLE, title); } fromActivity.startActivity(mapIntent); } public static void startActivityGeoCode(final Activity fromActivity, final String geocode) { final Intent mapIntent = newIntent(fromActivity); - mapIntent.putExtra(EXTRAS_MAP_MODE, MapMode.SINGLE); - mapIntent.putExtra(EXTRAS_LIVE_ENABLED, false); - mapIntent.putExtra(EXTRAS_GEOCODE, geocode); - mapIntent.putExtra(EXTRAS_MAP_TITLE, geocode); + mapIntent.putExtra(Intents.EXTRA_MAP_MODE, MapMode.SINGLE); + mapIntent.putExtra(Intents.EXTRA_LIVE_ENABLED, false); + mapIntent.putExtra(Intents.EXTRA_GEOCODE, geocode); fromActivity.startActivity(mapIntent); } |