/*
********************* [ P O C K E T C A M P U S ] *****************
* [ LICENCE ] see "licence"-file in the root directory
* [ MAINTAINER ] florian.laurent@epfl.ch
* [ STATUS ] stable
*
**************************[ C O M M E N T S ]**********************
*
* See the IMap class for methods documentation.
*
*******************************************************************
*/
package org.pocketcampus.map;
import java.util.HashSet;
import java.util.Set;
import org.andnav.osm.DefaultResourceProxyImpl;
import org.andnav.osm.ResourceProxy;
import org.andnav.osm.tileprovider.IRegisterReceiver;
import org.andnav.osm.util.GeoPoint;
import org.andnav.osm.views.OpenStreetMapView;
import org.andnav.osm.views.overlay.MyLocationOverlay;
import org.andnav.osm.views.util.IOpenStreetMapRendererInfo;
import org.pocketcampus.R;
import org.pocketcampus.gui.navigation.NavigationActivity;
import org.pocketcampus.map.bar.LevelBarFrameLayout;
import org.pocketcampus.map.element.MapElement;
import org.pocketcampus.map.overlay.MapElementsItemizedOverlay;
import org.pocketcampus.map.overlay.MapElementsOverlay;
import org.pocketcampus.map.overlay.MapPathOverlay;
import org.pocketcampus.map.overlay.OverlayBuilder;
import org.pocketcampus.map.renderer.RendererFactory;
import org.pocketcampus.map.renderer.RendererFactory.RendererName;
import org.pocketcampus.positioning.Locator;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class Map /* implements IMap */{
private final static double NORMAL_RADIUS_FOR_ONE_ELEMENT = 35.0;
private Context ctx_;
private Activity currentActivity_;
private EpflMapView view_;
private MyLocationOverlay myLocationOverlay_;
private SharedPreferences prefs_;
private IOpenStreetMapRendererInfo renderer_;
private EpflMapTilesOverlay EPFLBuildingOverlay_;
private MapElementsOverlay<MapElement> mapElementsOverlay_;
private RendererFactory rendererFactory_;
private MapElementsItemizedOverlay<MapElement> mapItemOverlay_;
private OverlayBuilder<MapElement> overlayBuilder_;
private MapPathOverlay<Position> mapPathOverlay_;
public ResourceProxy resourceProxy_;
private LevelBarFrameLayout lvlBarFrameLyt_;
// rendering options
private final boolean useEpflMapAsMain = true;
private final boolean useEpflMapAsOverlay = false;
private Locator locator_;
public Map(Context ctx, View mapView, Activity currentActivity) {
if (ctx == null || mapView == null || currentActivity == null)
throw new IllegalArgumentException();
ctx_ = ctx;
view_ = (EpflMapView) mapView;
currentActivity_ = currentActivity;
resourceProxy_ = new DefaultResourceProxyImpl(ctx_);
prefs_ = currentActivity_.getSharedPreferences("org.pocketcampus.map",
Activity.MODE_PRIVATE);
rendererFactory_ = new RendererFactory();
locator_ = Locator.getInstance(ctx);
setup();
}
// TODO move
private EpflMapTilesOverlay getOverlay(OpenStreetMapView view_,
Context ctx_, RendererName name, int level) {
IRegisterReceiver registerReceiver = new IRegisterReceiver() {
public Intent registerReceiver(BroadcastReceiver receiver,
IntentFilter filter) {
return null;
}
public void unregisterReceiver(BroadcastReceiver receiver) {
}
};
EpflMapTileProviderDirect mProvider = new EpflMapTileProviderDirect(
new Handler(), "key", registerReceiver);
return new EpflMapTilesOverlay(view_,
(new RendererFactory()).getRenderer(name, 0), mProvider, ctx_);
}
public void setup() {
// setting up everything...
if (useEpflMapAsOverlay) {
EPFLBuildingOverlay_ = getOverlay(view_, ctx_,
RendererName.EPFL_RENDERER, 1);
view_.getOverlays().add(EPFLBuildingOverlay_);
}
// setup view
view_.setResourceProxy(resourceProxy_);
view_.setBuiltInZoomControls(true);
view_.setMultiTouchControls(true);
// default position
view_.getController().setZoom(16);
centerMapOn(Locator.EPFL_CENTER, 500);
// setup overlays
myLocationOverlay_ = new MyLocationOverlay(ctx_, view_);
view_.getOverlays().add(myLocationOverlay_);
// mapElementsOverlay_ = new MapElementsOverlay<MapElement>(null,
// resourceProxy_);
overlayBuilder_ = new OverlayBuilder<MapElement>(currentActivity_,
null, resourceProxy_, this);
mapItemOverlay_ = overlayBuilder_.create();
view_.getOverlays().add(mapItemOverlay_);
mapPathOverlay_ = new MapPathOverlay<Position>(resourceProxy_);
view_.getOverlays().add(mapPathOverlay_);
// setup default preferences, save them
// myLocationOverlay_.enableMyLocation();
myLocationOverlay_.followLocation(false);
savePreferences();
// level changes markers
setupLevelChangesMarkers();
// forces multi-level display
setLevel(1);
}
private void savePreferences() {
final SharedPreferences.Editor edit = prefs_.edit();
edit.putInt("zoomLevel", view_.getZoomLevel());
edit.putBoolean("showLocation",
myLocationOverlay_.isMyLocationEnabled());
edit.putBoolean("followLocation",
myLocationOverlay_.isLocationFollowEnabled());
edit.commit();
}
/* CENTERING */
public void centerMapOn(MapElement el, double radius) {
centerMapOn(el.position(), radius);
}
private void centerMapOn(Position p, double radius) {
view_.getController().setCenter(new GeoPoint(p.getLat(), p.getLon()));
// this is an approximation, and doesn't take into account the fact
// that the screen may be bigger
// TODO do better
int zoomLevel = (int) (24 - Math.log(radius) / Math.log(2));
view_.getController().setZoom(zoomLevel);
}
public void centerMapOnEPFL(double radius) {
centerMapOn(Locator.EPFL_CENTER, radius);
}
public void centerMapOnPath() {
if (mapPathOverlay_.getPathCenter() == null) {
// no path currently displayed
return;
}
double radius = mapPathOverlay_.getPathRadius();
if (radius < 50) {
radius = 50;
}
centerMapOn(mapPathOverlay_.getPathCenter(), radius);
}
/* DRAWING */
/**
* displays a path on the map between mapElement and current UserPosition.
* If there is no current UserPositon, display only the MapElement.
*
* @param mapElement
* @param usingBike
*/
public void displayPathFromHereTo(MapElement mapElement, boolean usingBike) {
if (mapElement == null) {
Log.e("NavigationActivity", "Got a Null-MapElement to display. Abort!");
return;
}
// clearAll();
if (!locator_.isUserInEPFL()) {
Toast.makeText(
currentActivity_,
currentActivity_
.getString(R.string.Navigation_Toast_not_campus),
Toast.LENGTH_SHORT).show();
displaySingleMapElement(mapElement);
return;
}
clearPaths();
MapElement currentPosition = locator_.getUserMapElement();
if (currentPosition == null) {
Toast.makeText(currentActivity_,
R.string.Navigation_Toast_cannotGetYourPosition,
Toast.LENGTH_LONG).show();
Log.d("NavigationActivity",
"There is no currentPosition returned by getCurrentUserMapElement.");
displaySingleMapElement(mapElement);
return;
}
drawPathBetween(currentPosition, mapElement, usingBike);
centerMapOnPath();
}
/**
* Helper Method in order not to create a set any time when i only want to
* display one MapElement
*
* @param mapElement
*/
public void displaySingleMapElement(MapElement mapElement) {
if (mapElement == null) {
Log.e("NavigationActivity",
"Got a Null-MapElement to display. Abort!");
return;
}
// clearMapElements();
//clearPaths();
Set<MapElement> setOfOne = new HashSet<MapElement>();
setOfOne.add(mapElement);
centerMapOn(mapElement, NORMAL_RADIUS_FOR_ONE_ELEMENT);
drawMapElements(setOfOne);
}
public void drawMapElements(Set<MapElement> elems) {
if (elems == null)
return;
view_.getOverlays().remove(mapItemOverlay_);
overlayBuilder_.addMapElements(elems);
mapItemOverlay_ = overlayBuilder_.create();
view_.getOverlays().add(mapItemOverlay_);
}
public boolean drawPathBetween(MapElement start, MapElement end,
boolean bike) {
if (start == null || end == null)
return false;
if (start.equals(end))
return false;
setLevel(start.position().getLevel());
Path path = Search.searchPathBetween(start, end, bike);
if (path != null) {
mapPathOverlay_.setPath(path.getPositionList());
return true;
} else {
return false;
}
}
private void setupLevelChangesMarkers() {
Drawable levelUpIcon = ctx_.getResources().getDrawable(
R.drawable.navigation_level_up);
Drawable levelDownIcon = ctx_.getResources().getDrawable(
R.drawable.navigation_level_down);
Marker levelUpMarker = new Marker(levelUpIcon, 18, 18, new Point(9, 9));
Marker levelDownMarker = new Marker(levelDownIcon, 18, 18, new Point(9,
9));
mapPathOverlay_.setLevelDownMarker(levelDownMarker);
mapPathOverlay_.setLevelUpMarker(levelUpMarker);
}
// private boolean drawPathBetween(MapElement start, MapElement end, Marker
// levelUpMarker, Marker levelDownMarker, boolean bike) {
// mapPathOverlay_.setLevelDownMarker(levelDownMarker);
// mapPathOverlay_.setLevelUpMarker(levelUpMarker);
//
// return drawPathBetween(start, end, bike);
// }
/* CLEARING */
public void clearAll() {
clearPaths();
clearMapElements();
//draw current user position again (should always be displayed)
if (locator_.isUserInEPFL()) {
displaySingleMapElement(locator_.getUserMapElement());
}
}
public void clearPaths() {
mapPathOverlay_.clear();
view_.invalidate();
}
public void clearMapElements() {
view_.getOverlays().remove(mapItemOverlay_);
overlayBuilder_.clear();
mapItemOverlay_ = overlayBuilder_.create();
view_.getOverlays().add(mapItemOverlay_);
view_.invalidate();
}
/* CALLED FROM MAIN ACTIVITY */
public void resume() {
// restore preferences
if (prefs_.getBoolean("showLocation", false))
myLocationOverlay_.enableMyLocation();
myLocationOverlay_.followLocation(prefs_.getBoolean("followLocation",
false));
}
public void pause() {
// don't empty user's battery with GPS while he isn't looking...
myLocationOverlay_.disableMyLocation();
savePreferences();
}
/* LEVEL */
public void setLevel(int level) {
if (lvlBarFrameLyt_ != null)
lvlBarFrameLyt_.setValue(level);
if (useEpflMapAsMain) {
if (level >= -2 && level <= 4)
renderer_ = rendererFactory_.getRenderer(
RendererFactory.RendererName.EPFL_RENDERER, level);
view_.setRenderer(renderer_);
view_.invalidate();
}
if (useEpflMapAsOverlay) {
EPFLBuildingOverlay_ = getOverlay(view_, ctx_,
RendererName.EPFL_RENDERER, level);
}
}
public void addLevelBar(LevelBarFrameLayout lvlBarFrameLyt) {
lvlBarFrameLyt_ = lvlBarFrameLyt;
}
/* LISTENERS */
public boolean trackballEvent(MotionEvent event) {
view_.onTouchEvent(event);
return view_.onTrackballEvent(event);
}
public boolean touchEvent(MotionEvent event) {
return view_.onTouchEvent(event);
}
public void clearCache() {
ctx_ = null;
view_.clear();
if (useEpflMapAsOverlay) {
EPFLBuildingOverlay_.clear();
}
Log.d("Memory", "Map cache flushed!");
}
}
|