Map.java :  » App » pocketcampus » org » pocketcampus » map » Android Open Source

Android Open Source » App » pocketcampus 
pocketcampus » org » pocketcampus » map » Map.java
/*
 ********************* [ 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!");
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.