//Created by plusminus on 17:13:04 - 12.02.2008
package org.androad.ui.map;
import java.io.IOException;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.osmdroid.tileprovider.MapTile;
import org.osmdroid.tileprovider.MapTileProviderBase;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.ScaleBarOverlay;
import org.osmdroid.views.MapView.Projection;
import org.osmdroid.views.MapController.AnimationType;
import org.osmdroid.views.overlay.ItemizedOverlayControlView;
import org.osmdroid.views.overlay.Overlay;
import org.osmdroid.views.overlay.OverlayManager;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.androad.R;
import org.androad.adt.AndNavLocation;
import org.androad.adt.UnitSystem;
import org.androad.adt.voice.AudibleTurnCommand;
import org.androad.adt.voice.DirectionVoiceCommandListener;
import org.androad.adt.voice.DistanceVoiceElement;
import org.androad.adt.voice.SimpleAudibleTurnCommand;
import org.androad.adt.voice.TurnVoiceElement;
import org.androad.exc.Exceptor;
import org.androad.nav.Navigator;
import org.androad.nav.OffRouteListener;
import org.androad.nav.WayPointListener;
import org.androad.nav.WaypointOptimizer;
import org.androad.nav.stats.StatisticsManager;
import org.androad.nav.util.NavAlgorithm;
import org.androad.osm.views.overlay.util.DirectionArrowDescriptor;
import org.androad.osm.views.tiles.util.OSMMapTilePreloader;
import org.androad.preferences.PreferenceConstants;
import org.androad.preferences.Preferences;
import org.androad.sound.ISoundManager;
import org.androad.sound.MediaPlayerManager;
import org.androad.sound.tts.SpeechImprover;
import org.androad.sys.ors.adt.aoi.AreaOfInterest;
import org.androad.sys.ors.adt.aoi.CircleByCenterPoint;
import org.androad.sys.ors.adt.lus.Country;
import org.androad.sys.ors.adt.rs.DirectionsLanguage;
import org.androad.sys.ors.adt.rs.Route;
import org.androad.sys.ors.adt.rs.RouteInstruction;
import org.androad.sys.ors.adt.rs.RoutePreferenceType;
import org.androad.sys.ors.aps.APSRequester;
import org.androad.sys.ors.exceptions.ORSException;
import org.androad.sys.ors.rs.RSOfflineLoader;
import org.androad.sys.ors.rs.RouteFactory;
import org.androad.sys.ors.views.overlay.AreaOfInterestOverlay;
import org.androad.ui.common.CommonCallback;
import org.androad.ui.common.CommonDialogFactory;
import org.androad.ui.common.views.RotateView;
import org.androad.ui.map.hud.IHUDImpl;
import org.androad.ui.map.overlay.MapDrivingDirectionsOverlay;
import org.androad.ui.sd.SDMainChoose;
import org.androad.ui.sd.SDPOISearchList;
import org.androad.ui.settings.SettingsMenu;
import org.androad.ui.settings.SettingsRoutingFlags;
import org.androad.ui.util.Util;
import org.androad.util.FileSizeFormatter;
import org.androad.util.UserTask;
import org.androad.util.constants.Constants;
import org.xml.sax.SAXException;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.speech.tts.TextToSpeech;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
import android.text.style.StyleSpan;
import android.util.Log;
import android.view.ContextMenu;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager.BadTokenException;
import android.widget.ImageView;
import android.widget.Toast;
public class OpenStreetDDMap extends OpenStreetMapAndNavBaseActivity implements OffRouteListener, DirectionVoiceCommandListener, WayPointListener, PreferenceConstants, Constants {
private final int TIME_BETWEEN_MISS_REFETCH = 8000;
private static final int MAPFETCH_TRIES_TO_GET_GPS = 10;
private static final int MAPFETCH_TRIES_TO_GET_ROUTE = 2;
/** Time in milliseconds the Autozooming is disabled, after the zoombuttons were used. */
private static final int AUTOZOOM_BLOCKTIME = 12000;
/** Time in milliseconds the Autocentering is disabled, after the user panned the map. */
private static final int AUTOCENTER_BLOCKTIME = 8000;
private static final boolean INITDRIVINGDIRECTIONS_NEWROUTE = false;
/** Used when the Route needs to be just restored, after a call to <code>onRestoreInstanceState</code>, which probably was caused by a Configuration-change, like the a change of the Scree-Orientation. */
private static final boolean INITDRIVINGDIRECTIONS_RESTORE = true;
private static final String STATE_WAYPOINTS_ID = "state_waypoints_id";
private static final String STATE_STATICNAVCURRENT_ID = "state_liteversioncurrent_id";
private static final String STATE_STATICNAVNEXT_ID = "state_liteversionnext_id";
private static final String STATE_DOAUTOMATICROUTEREFETCH_ID = "state_doautomaticrouterefetch_id";
private static final String STATE_INITIALROUTEFETCH_ID = "state_initialroutefetch_id";
private static final String STATE_ROUTE_ID = "state_route_id";
private static final String STATE_LASTWORKINGROUTE_ID = "state_lastworkingroute_id";
// ===========================================================
// Final Fields
// ===========================================================
/* REQUEST-CODES for SubActivities. */
private static final int REQUESTCODE_SETTINGS = 0x1937;
private static final int REQUESTCODE_SD_WAYPOINT = REQUESTCODE_SETTINGS + 1;
private static final int REQUESTCODE_ROUTINGFLAGS = REQUESTCODE_SD_WAYPOINT + 1;
public static final int OFF_ROUTE = 0;
public static final int ON_ROUTE = OFF_ROUTE + 1;
public static final int REFETCHING_ROUTE = ON_ROUTE + 1;
private static final int MENU_SETTINGS_ID = Menu.FIRST;
private static final int MENU_REFETCH_ROUTE_ID = MENU_SETTINGS_ID + 1;
private static final int MENU_QUIT_ID = MENU_REFETCH_ROUTE_ID + 1;
private static final int MENU_SUBMENU_RENDERERS_ID = MENU_QUIT_ID + 1;
private static final int MENU_SATELLITE_ID = MENU_SUBMENU_RENDERERS_ID + 1;
private static final int MENU_TRAFFIC_ID = MENU_SATELLITE_ID + 1;
private static final int MENU_SUBWAYPOINTS_ID = MENU_TRAFFIC_ID + 1;
private static final int MENU_WAYPOINT_ADD_ID = MENU_SUBWAYPOINTS_ID + 1;
private static final int MENU_WAYPOINTS_CLEAR_ID = MENU_WAYPOINT_ADD_ID + 1;
private static final int MENU_WAYPOINTS_OPTIMIZE_ID = MENU_WAYPOINTS_CLEAR_ID + 1;
private static final int MENU_PRELOADTILES_ID = MENU_WAYPOINTS_OPTIMIZE_ID + 1;
private static final int MENU_REVERSEROUTE_ID = MENU_PRELOADTILES_ID + 1;
private static final int MENU_ROUTEINSTRUCTIONS_ID = MENU_REVERSEROUTE_ID + 1;
private static final int MENU_ALTITUDEPROFILE_ID = MENU_ROUTEINSTRUCTIONS_ID + 1;
private static final int MENU_SHAREROUTE_ID = MENU_ALTITUDEPROFILE_ID + 1;
private static final int MENU_GPSSTATUS_ID = MENU_SHAREROUTE_ID + 1;
private static final int MENU_ZOOMTODESTINATION_ID = MENU_GPSSTATUS_ID + 1;
private static final int MENU_SUBMENU_LAYERS_OFFSET = 1000;
private static final int CONTEXTMENU_ADDASWAYPOINT = Menu.FIRST;
private static final int CONTEXTMENU_CLEARWAYPOINTS = CONTEXTMENU_ADDASWAYPOINT + 1;
private static final int CONTEXTMENU_CLOSE = CONTEXTMENU_CLEARWAYPOINTS + 1;
private static final int DIALOG_SHOW_ALTITUDE_PROFILE = 0;
// ===========================================================
// Fields
// ===========================================================
private Bitmap mCurrentAltitudeProfileBitmap;
/** The Destination {@link GeoPoint} of the route. */
private GeoPoint mGPDestination;
/** The Start {@link GeoPoint} of the current route. */
private GeoPoint mGPStart;
/** The Start {@link GeoPoint} of the very first route. */
private GeoPoint mGPStartInitial;
private boolean mDoAutomaticRouteRefetch = true;
/** Holds the timestamp until the AutoZoom is blocked, because the user has used the Zoom-Buttons. */
private long mAutoZoomBlockedUntil = 0;
/** Holds the timestamp until the AutoCentering is blocked, because the user has panned the map. */
private long mAutoCenterBlockedUntil = 0;
private TextToSpeech mTTS;
private boolean mTTSAvailable = false;
private boolean mRealtimeNav = true;
private int mStaticNavCurrentTurnIndex = Constants.NOT_SET;
private int mStaticNavNextTurnIndex = Constants.NOT_SET;
private AreaOfInterestOverlay mAreaOfAvoidingsOverlay;
private final ArrayList<AreaOfInterest> mAvoidAreas = new ArrayList<AreaOfInterest>();
private ItemizedOverlayControlView mMapItemControlView;
private ScaleBarOverlay mScaleIndicatorView;
/**
* Indicates whether direction voice is enabled.
* Loaded from Preferences in onResume().
*/
private boolean mDirectionVoiceEnabled = false;
private ISoundManager mSoundManager;
/**
* Indicates whether driving-statistics are generated.
* Loaded from Preferences in onResume().
*/
private boolean mStatisticsEnabled = false;
private StatisticsManager mStatisticsManager;
private HashMap<Integer, Integer> mTurnVoiceSayList;
private ImageView mIvRouteStatus;
private Drawable mOffRouteDrawable;
private Drawable mRouteRefetchDrawable;
private IHUDImpl mHUDImpl;
private ArrayList<GeoPoint> mWayPoints = new ArrayList<GeoPoint>();
private Route mRoute;
private Route mLastWorkingRoute;
private ArrayList<GeoPoint> mLastWorkingWayPoints = new ArrayList<GeoPoint>();
private Navigator mNavigator;
private RotateView mMapRotateView;
private MapDrivingDirectionsOverlay mMyMapDrivingDirectionsOverlay = null;
private ProgressDialog mRouteFetchProgressDialog;
private Bundle mBundleCreatedWith;
private GeoPoint mGPLastMapClick;
private int mCenterMode = PREF_CENTERMODE_DEFAULT;
private int mRotateMode = PREF_ROTATEMODE_DEFAULT;
private boolean mSnapToRouteEnabled = PREF_SNAPTOROUTE_DEFAULT;
private int mSnapToRouteRadius = PREF_SNAPTOROUTE_RADIUS_DEFAULT;
private boolean mAutoZoomEnabled = PREF_AUTOZOOM_DEFAULT;
private DirectionsLanguage mDrivingDirectionsLanguage;
private int mOnRouteStatus = REFETCHING_ROUTE;
private boolean mRouteRefetchRunning = true;
/** Got created by the GUI-Thread and there for can create i.e. Toasts. */
private final Handler mRefetchTriggerHandler = new Handler();
/** The country this route is being in. */
private Country mRouteCountry;
/**
* Only true on the very first call of
* kickOffDialog/startFecthingDirections. Males the GoogleMaps-Logo
* disappear.
*/
private boolean mInitialRouteFetch = true;
private PowerManager.WakeLock mWakeLock;
private final TextToSpeech.OnInitListener mTTSInitListener = new TextToSpeech.OnInitListener() {
@Override
public void onInit(final int version) {
// OpenStreetDDMap.this.mTTS.setLanguage(Locale.US);
// OpenStreetDDMap.this.mTTS.setSpeechRate(130);
initGeneratedVoice();
OpenStreetDDMap.this.mTTSAvailable = true;
}
};
private final Runnable mRefetchRunner = new Runnable() {
@Override
public void run() {
if (OpenStreetDDMap.this.mDoAutomaticRouteRefetch){
/* Check if still true (route was not resumed in between). */
if(OpenStreetDDMap.this.mRouteRefetchRunning) {
if (OpenStreetDDMap.this.mOnRouteStatus != REFETCHING_ROUTE) {
if (OpenStreetDDMap.this.mDirectionVoiceEnabled) {
OpenStreetDDMap.this.mSoundManager.playSound(R.raw.refetching_route);
}
OpenStreetDDMap.this.mIvRouteStatus.setImageDrawable(OpenStreetDDMap.this.mRouteRefetchDrawable);
OpenStreetDDMap.this.mIvRouteStatus.setVisibility(View.VISIBLE);
Log.d(Constants.DEBUGTAG, "RE-Fetching Route!");
try {
/* Start a "REfetching route"-dialog. */
OpenStreetDDMap.this.kickOffRouteFetch();
} catch (final BadTokenException bte) {
/*
* Thrown when this ProgressDialog.show() is called and
* Activity is already ended. Can happen because of we
* are calling postDelayed!
*/
}
}
}
}
}
};
// ===========================================================
// "Constructor"
// ===========================================================
/** Called when the activity is first created. */
@Override
public void onCreate(final Bundle savedInstanceState) {
Log.d(Constants.DEBUGTAG, "OnCREATE");
super.onCreate(savedInstanceState);
this.mRealtimeNav = Preferences.getRealTimeNav(this);
/*
* Retrieve the Extras Bundle of the Intent this Activity was created
* with, because it contains the Information, to be used for retrievign the Route API.
*/
this.mBundleCreatedWith = this.getIntent().getExtras();
this.mRouteCountry = this.mBundleCreatedWith.getParcelable(EXTRAS_COUNTRY_ID);
this.mTTS = new TextToSpeech(this, this.mTTSInitListener);
final int searchMode = OpenStreetDDMap.this.mBundleCreatedWith.getInt(EXTRAS_MODE);
switch(searchMode){
case EXTRAS_MODE_LOAD_SAVED_ROUTE:
this.mDoAutomaticRouteRefetch = false;
break;
default:
this.mDoAutomaticRouteRefetch = true;
break;
}
this.mSoundManager = MediaPlayerManager.getInstance(this);
final int displayQuality = Preferences.getDisplayQuality(this);
this.mHUDImpl.getRemainingSummaryView().setDisplayQuality(displayQuality);
this.mHUDImpl.getNextActionView().setDisplayQuality(displayQuality);
this.mHUDImpl.getUpperNextActionView().setDisplayQuality(displayQuality);
/* Load the ItemizedControlView. */
this.mMapItemControlView = (ItemizedOverlayControlView)findViewById(R.id.itemizedoverlaycontrol_ddmap);
/* This code together with the one in onResume() will make the screen be always on during navigation. */
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyWakeLock");
this.mWakeLock.acquire();
/* CleanUp a maybe dead previous statistic session. */
Preferences.cleanStatisticsSession(this);
/* Make the system know we want to control the volume on the MUSIC-STREAM with the Hardware-Buttons. */
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
this.applyViewListeners();
this.applyMapViewLongPressListener();
final UnitSystem unitSystem = Preferences.getUnitSystem(this);
this.mHUDImpl.getNextActionView().setUnitSystem(unitSystem);
this.mHUDImpl.getUpperNextActionView().setUnitSystem(unitSystem);
this.mHUDImpl.getRemainingSummaryView().setUnitSystem(unitSystem);
this.mNavigator = new Navigator(this, unitSystem);
this.mNavigator.setOffTrackListener(this); // TODO auch zu !REALTIMENAV ?
this.mNavigator.setWayPointListener(this); // TODO auch zu !REALTIMENAV ?
// TODO if(searchMode == EXTRAS_MODE_LOAD_SAVED_ROUTE) show only realtime/static option.
if(savedInstanceState != null){
// Nothing (initDrivingDirections gets called through onRestoreInstanceState)
}else if(Preferences.getNavSettingsRemember(this) || searchMode == EXTRAS_MODE_LOAD_SAVED_ROUTE){
initDrivingDirections(INITDRIVINGDIRECTIONS_NEWROUTE);
}else{
final Intent getFlagsIntent = new Intent(this, SettingsRoutingFlags.class);
final Bundle b = new Bundle();
b.putBoolean(SettingsRoutingFlags.IS_DIALOG_MODE, true);
getFlagsIntent.putExtras(b);
startActivityForResult(getFlagsIntent, REQUESTCODE_ROUTINGFLAGS);
}
}
@Override
protected void onSetupContentView() {
this.mHUDImpl = Preferences.getHUDImpl(this);
final int variationID = Preferences.getHUDImplVariationID(this);
this.setContentView(this.mHUDImpl.getVariation(variationID).getLayoutID());
this.mHUDImpl.init(this.findViewById(R.id.ddmap_root));
super.mOSMapView = (MapView) findViewById(R.id.map_ddmap);
super.mOSMapView.setTileSource(Preferences.getMapViewProviderInfoDDMap(this));
this.mMapRotateView = (RotateView) findViewById(R.id.rotator_ddmap);
this.mIvRouteStatus = (ImageView) findViewById(R.id.iv_ddmap_offroute);
final Resources resources = getResources();
this.mOffRouteDrawable = resources.getDrawable(R.drawable.route_missed);
this.mRouteRefetchDrawable = resources.getDrawable(R.drawable.route_refetch);
final int displayQuality = Preferences.getDisplayQuality(this);
final OverlayManager overlaymanager = this.mOSMapView.getOverlayManager();
this.mScaleIndicatorView = new ScaleBarOverlay(this);
if (Preferences.getUnitSystem(this) == UnitSystem.IMPERIAL) {
this.mScaleIndicatorView.setImperial();
} else {
this.mScaleIndicatorView.setMetric();
}
this.mScaleIndicatorView.setScaleBarOffset(getResources().getDisplayMetrics().widthPixels/2 - getResources().getDisplayMetrics().xdpi/2, 10);
overlaymanager.add(this.mScaleIndicatorView);
/* Add a new instance of our fancy Overlay-Class to the MapView. */
final DirectionArrowDescriptor pDirectionArrowDescriptor = Preferences.getHUDImplVariationDirectionArrowDescriptor(this);
this.mMyMapDrivingDirectionsOverlay = new MapDrivingDirectionsOverlay(this, displayQuality, this.mRealtimeNav, pDirectionArrowDescriptor);
/* The AvoidArea-Overlay. */
this.mAreaOfAvoidingsOverlay = new AreaOfInterestOverlay(this, this.mAvoidAreas);
overlaymanager.add(this.mMyMapDrivingDirectionsOverlay);
overlaymanager.add(this.mAreaOfAvoidingsOverlay);
}
/**
* @see INITDRIVINGDIRECTIONS_NEWROUTE or INITDRIVINGDIRECTIONS_JUSTREFRESH
* @param pRestore <code>true</code> to just re-initlalize the objects that working on <code>mRoute</code> like the navigator.<br/>
* <code>false</code> will in the end overwrite <code>mRoute</code> and the initialize the objects working on it.
*/
private void initDrivingDirections(final boolean pRestore) {
initStaticNavControlsIfNeccessary();
/* Start the "fetching route"-dialog. */
this.mRefetchTriggerHandler.postDelayed(new Runnable() {
public void run() {
OpenStreetDDMap.this.kickOffRouteFetch(pRestore);
}
}, 500);
}
/** Makes the */
private void initStaticNavControlsIfNeccessary() {
if(!this.mRealtimeNav){
/* Initialize the Overlay-Cotrol*/
this.mMapItemControlView.setVisibility(View.VISIBLE);
this.mMapItemControlView.setNavToVisible(View.GONE);
this.mMapItemControlView.setPreviousEnabled(false);
this.mMapItemControlView.setNextEnabled(false);
this.mMapItemControlView.setItemizedOverlayControlViewListener(new StaticNavOverlayControlView());
}
}
private void initGeneratedVoice() {
// final String pkgName = AndRoadApplication.class.getPackage().getName(); // Root Package!
}
// ===========================================================
// Getter & Setter
// ===========================================================
public MapView getMapView() {
return this.mOSMapView;
}
public float getMetersDrivenThisSession() {
return this.mStatisticsManager.getMetersScaleDrivenSession();
}
public Navigator getNavigator() {
return this.mNavigator;
}
public Route getRoute() {
return this.mRoute;
}
/**
* Between 1 (far) and 21 (closest).
* @return the zoomLevel
*/
public int getZoomLevel() {
return this.mOSMapView.getZoomLevel();
}
// ===========================================================
// Methods from SuperClass/Interfaces
// ===========================================================
@Override
protected Dialog onCreateDialog(final int id) {
switch(id){
case DIALOG_SHOW_ALTITUDE_PROFILE:
return CommonDialogFactory.createAltitudeProfileDialog(this, new CommonCallback<Void>(){
@Override
public void onSuccess(final Void result) {
if(OpenStreetDDMap.this.mCurrentAltitudeProfileBitmap != null) {
OpenStreetDDMap.this.mCurrentAltitudeProfileBitmap.recycle();
}
}
@Override
public void onFailure(final Throwable t) {
if(OpenStreetDDMap.this.mCurrentAltitudeProfileBitmap != null) {
OpenStreetDDMap.this.mCurrentAltitudeProfileBitmap.recycle();
}
}
});
default:
return null;
}
}
@Override
protected void onPrepareDialog(final int id, final Dialog dialog) {
switch(id){
case DIALOG_SHOW_ALTITUDE_PROFILE:
CommonDialogFactory.prepareAltitudeProfileDialog(this, dialog, this.mCurrentAltitudeProfileBitmap);
return;
}
}
/**
* @return May return the projected location instead of the actual location, depending on <code>mSnapToRouteEnabled</code>.
*/
public GeoPoint getLastKnownLocationAsGeoPoint(final boolean pUseRemembered) {
final GeoPoint actualLocation = super.getLastKnownLocation(pUseRemembered);
if(actualLocation != null && this.mSnapToRouteEnabled){
final GeoPoint projectedLocation = this.mNavigator.getLastKnownLocationProjectedGeoPoint();
if(projectedLocation != null){
final int differenceOfProjectionToActual = actualLocation.distanceTo(projectedLocation);
if(differenceOfProjectionToActual < this.mSnapToRouteRadius){
return projectedLocation;
}else{
return actualLocation;
}
}else{
return actualLocation;
}
}else{
return actualLocation;
}
}
@Override
public void release(){
this.mRouteRefetchDrawable = null;
this.mOffRouteDrawable = null;
}
@Override
public void onDataStateChanged(final int strength) {
// TODO Nothing?
}
@Override
public boolean onKeyDown(final int keyCode, final KeyEvent event) {
switch(keyCode){
case KeyEvent.KEYCODE_R:
this.mRouteRefetchRunning = false; // TODO Check if it should be really false
this.mDoAutomaticRouteRefetch = true;
kickOffRouteFetch();
return true;
case KeyEvent.KEYCODE_A:
this.mAutoZoomEnabled = !this.mAutoZoomEnabled;
if(this.mAutoZoomEnabled) {
Toast.makeText(this, R.string.toast_autozoom_enabled, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, R.string.toast_autozoom_disabled, Toast.LENGTH_SHORT).show();
}
return true;
case KeyEvent.KEYCODE_S:
this.mSnapToRouteEnabled = !this.mSnapToRouteEnabled;
if(this.mSnapToRouteEnabled) {
Toast.makeText(this, R.string.toast_snaptoroute_enabled, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, R.string.toast_snaptoroute_disabled, Toast.LENGTH_SHORT).show();
}
return true;
case KeyEvent.KEYCODE_SEARCH:
startWaypointActivity();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
menu.setQwertyMode(true);
int menuPos = Menu.FIRST;
{ // Settings-Item
menu.add(menuPos, MENU_SETTINGS_ID, menuPos, getString(R.string.maps_menu_settings))
.setIcon(R.drawable.settings)
.setAlphabeticShortcut('s');
menuPos++;
}
{ // Renderers-SubMenuItem
final SubMenu subMenu = menu.addSubMenu(menuPos, MENU_SUBMENU_RENDERERS_ID, menuPos, getString(R.string.maps_menu_submenu_renderers)).setIcon(R.drawable.layers);
menuPos++;
{
final ITileSource[] providers = TileSourceFactory.getTileSources().toArray(new ITileSource[0]);
for(int j = 0; j < providers.length; j ++){
final SpannableString itemTitle = new SpannableString(providers[j].name());
itemTitle.setSpan(new StyleSpan(Typeface.ITALIC), providers[j].name().length(), itemTitle.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
itemTitle.setSpan(new RelativeSizeSpan(0.5f), providers[j].name().length(), itemTitle.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
subMenu.add(0, MENU_SUBMENU_LAYERS_OFFSET + j, Menu.NONE, itemTitle);
}
}
}
{ // Waypoints-SubMenuItem
final SubMenu waypointsSubMenu = menu.addSubMenu(menuPos, MENU_SUBWAYPOINTS_ID, menuPos, getString(R.string.maps_menu_submenu_waypoints)).setIcon(R.drawable.waypoint);
menuPos++;
{
waypointsSubMenu.add(0, MENU_WAYPOINT_ADD_ID, Menu.NONE, getString(R.string.maps_menu_waypoint_add))
.setIcon(R.drawable.waypoint)
.setAlphabeticShortcut('a');
waypointsSubMenu.add(1, MENU_WAYPOINTS_OPTIMIZE_ID, Menu.NONE, getString(R.string.maps_menu_waypoints_optimize))
.setIcon(R.drawable.optimize)
.setAlphabeticShortcut('o');
waypointsSubMenu.add(2, MENU_WAYPOINTS_CLEAR_ID, Menu.NONE, getString(R.string.maps_menu_waypoints_clear))
.setIcon(R.drawable.wipe)
.setAlphabeticShortcut('w');
}
}
{ // Refetch-Item
menu.add(menuPos, MENU_REFETCH_ROUTE_ID, menuPos, getString(R.string.maps_menu_refetch_route))
.setIcon(R.drawable.route_refetch)
.setAlphabeticShortcut('r');
menuPos++;
}
{ // Preload-Item
menu.add(menuPos, MENU_PRELOADTILES_ID, menuPos, getString(R.string.maps_menu_preload))
.setIcon(R.drawable.preload)
.setAlphabeticShortcut('p');
menuPos++;
}
{ // ReverseRoute-Item
menu.add(menuPos, MENU_REVERSEROUTE_ID, menuPos, getString(R.string.maps_menu_reverseroute))
.setIcon(R.drawable.refresh)
.setAlphabeticShortcut('a');
menuPos++;
}
{ // ShareRoute-Item
menu.add(menuPos, MENU_SHAREROUTE_ID, menuPos, getString(R.string.maps_menu_shareroute))
.setIcon(R.drawable.share_route)
.setAlphabeticShortcut('m');
menuPos++;
}
{ // Route Instructions
menu.add(menuPos, MENU_ROUTEINSTRUCTIONS_ID, menuPos, getString(R.string.maps_menu_routeinstructions))
.setIcon(R.drawable.turn_right_90)
.setAlphabeticShortcut('i');
menuPos++;
}
{ // Altitude Profile-Item
menu.add(menuPos, MENU_ALTITUDEPROFILE_ID, menuPos, getString(R.string.maps_menu_altitude_profile))
.setIcon(R.drawable.altitude_profile)
.setAlphabeticShortcut('h');
menuPos++;
}
{ // GPS-Status-Item
menu.add(menuPos, MENU_GPSSTATUS_ID, menuPos, getString(R.string.maps_menu_gpsstatus))
.setIcon(R.drawable.gps_status)
.setAlphabeticShortcut('g');
menuPos++;
}
{ // GPS-Status-Item
menu.add(menuPos, MENU_ZOOMTODESTINATION_ID, menuPos, getString(R.string.maps_menu_zoomtodestination))
.setIcon(R.drawable.zoom_in) // Icon CHECK to big?
.setAlphabeticShortcut('z');
menuPos++;
}
{
// TODO Avoid-Area SubMenu, just like WayPoints.
}
{ // Close-Item
if(menu.size() <= 5){ // If there will be no 'more'-item
menu.add(menuPos, MENU_QUIT_ID, menuPos, getString(R.string.maps_menu_quit))
.setIcon(R.drawable.exit)
.setAlphabeticShortcut('q');
}else{
// Place it as the fifth.
menu.add(4, MENU_QUIT_ID, 4, getString(R.string.maps_menu_quit))
.setIcon(R.drawable.exit)
.setAlphabeticShortcut('q');
}
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onMenuItemSelected(final int featureId, final MenuItem item) {
final int itemId = item.getItemId();
switch(itemId){
case MENU_REFETCH_ROUTE_ID:
this.mRouteRefetchRunning = false; // TODO Check if it should be really false
this.mDoAutomaticRouteRefetch = true;
kickOffRouteFetch();
return true;
case MENU_SETTINGS_ID:
final Intent settingsIntent = new Intent(this, SettingsMenu.class);
startActivityForResult(settingsIntent, REQUESTCODE_SETTINGS);
return true;
case MENU_GPSSTATUS_ID:
org.androad.ui.util.Util.startUnknownActivity(this, "com.eclipsim.gpsstatus.VIEW", "com.eclipsim.gpsstatus");
return true;
case MENU_WAYPOINT_ADD_ID:
startWaypointActivity();
return true;
case MENU_PRELOADTILES_ID:
startPreloadTilesDialog();
return true;
case MENU_WAYPOINTS_CLEAR_ID:
this.mWayPoints.clear();
this.kickOffRouteFetch();
return true;
case MENU_SHAREROUTE_ID:
handleShareRoute(OpenStreetDDMap.this.mRoute.getRouteHandleID());
return true;
case MENU_ROUTEINSTRUCTIONS_ID:
routeInstructions();
return true;
case MENU_ZOOMTODESTINATION_ID:
zoomToDestination();
return true;
case MENU_WAYPOINTS_OPTIMIZE_ID:
final List<GeoPoint> vias = this.mRoute.getVias();
final boolean change = WaypointOptimizer.optimize(this.getLastKnownLocationAsGeoPoint(true), vias, this.mRoute.getDestination());
if (change) {
this.mWayPoints.clear();
for (final GeoPoint gp : vias) {
this.mWayPoints.add(gp);
}
this.kickOffRouteFetch();
} else {
Toast.makeText(this, "Already optimized", Toast.LENGTH_SHORT).show();
}
return true;
case MENU_ALTITUDEPROFILE_ID:
showAltitudeProfile();
return true;
case MENU_REVERSEROUTE_ID:
Collections.reverse(this.mWayPoints);
final GeoPoint tmp = this.mGPStartInitial;
this.mGPStartInitial = this.mGPDestination;
this.mGPDestination = tmp;
this.kickOffRouteFetch(this.mGPStartInitial); // Use the old destination as start
return true;
case MENU_QUIT_ID:
this.setResult(SUBACTIVITY_RESULTCODE_CHAINCLOSE_QUITTED);
this.finish();
return true;
default:
if(itemId >= MENU_SUBMENU_LAYERS_OFFSET){
final ITileSource provider = TileSourceFactory.getTileSources().toArray(new ITileSource[0])[item.getItemId() - MENU_SUBMENU_LAYERS_OFFSET];
/* Check if Auto-Follow has to be disabled. */
/* Remember changes to the provider to start the next time with the same provider. */
Preferences.saveMapViewProviderInfoDDMap(this, provider);
this.mOSMapView.setTileSource(provider);
return true;
}
}
return super.onMenuItemSelected(featureId, item);
}
private void routeInstructions() {
final Intent intent = new Intent(this, RouteInstructions.class);
final Bundle b = new Bundle();
b.putParcelable(RouteInstructions.class.getName(), this.mRoute);
intent.putExtra(RouteInstructions.class.getName(), b);
startActivity(intent);
}
private void zoomToDestination() {
this.mAutoZoomBlockedUntil = System.currentTimeMillis() + AUTOZOOM_BLOCKTIME;
this.mAutoCenterBlockedUntil = System.currentTimeMillis() + AUTOCENTER_BLOCKTIME;
this.mOSMapView.getController().stopAnimation(false);
this.mOSMapView.getController().zoomInFixing(this.mRoute.getDestination());
}
private void handleShareRoute(final long pRouteHandleID) {
Util.openEmail(this,
"Hi,\n\nHave a look at this AndRoad-route:\nRouteHandleID = " + pRouteHandleID + "\n\nSee you =)\n\n\nTo view the route, open AndRoad, then open the Map and type the RouteHandleID from above to the SearchBox.",
"AndRoad Shared Route",
null);
}
private void showAltitudeProfile() {
if(this.mRoute == null){
}else{
Toast.makeText(OpenStreetDDMap.this, R.string.please_wait_a_moment, Toast.LENGTH_LONG).show();
new UserTask<Route, Void, Bitmap>(){
@Override
public Bitmap doInBackground(final Route... pRoute) {
try {
int startIndex = (OpenStreetDDMap.this.mNavigator.isReady()) ? OpenStreetDDMap.this.mNavigator.getNextRoutePointIndex() : 0;
if(startIndex == Constants.NOT_SET) {
startIndex = 0;
}
return APSRequester.request(pRoute[0].getPolyLine(), startIndex);
} catch (final Exception e){
return null;
}
}
@Override
public void onPostExecute(final Bitmap result) {
super.onPostExecute(result);
OpenStreetDDMap.this.mCurrentAltitudeProfileBitmap = result;
showDialog(DIALOG_SHOW_ALTITUDE_PROFILE);
}
}.execute(this.mRoute);
}
}
@Override
public boolean onPrepareOptionsMenu(final Menu menu) {
menu.findItem(MENU_PRELOADTILES_ID).setEnabled(this.mRoute != null);
menu.findItem(MENU_SHAREROUTE_ID).setVisible(this.mRoute != null && this.mRoute.hasRouteHandleID());
final MenuItem refetchMenuItem = menu.findItem(MENU_REFETCH_ROUTE_ID);
refetchMenuItem.setVisible(!this.mRealtimeNav || !this.mDoAutomaticRouteRefetch);
if(!this.mDoAutomaticRouteRefetch) {
refetchMenuItem.setTitle(R.string.maps_menu_auto_refetch);
} else if(!this.mRealtimeNav) {
refetchMenuItem.setTitle(R.string.maps_menu_refetch_route);
}
final MenuItem reverseRouteMenuItem = menu.findItem(MENU_REVERSEROUTE_ID);
reverseRouteMenuItem.setEnabled(this.mGPStart != null && this.mGPDestination != null);
return super.onPrepareOptionsMenu(menu);
}
private void startPreloadTilesDialog() {
startPreloadTilesDialog(this.mOSMapView.getZoomLevel());
}
private void startPreloadTilesDialog(final int zoomLevel) {
if(this.mRoute == null){
Toast.makeText(this, R.string.toast_preloader_noroute, Toast.LENGTH_SHORT).show();
return;
}
final MapTileProviderBase rendererInfo = this.mOSMapView.getTileProvider();
final ArrayList<MapTile> tilesNeeded = OSMMapTilePreloader.getNeededMaptiles(this.mRoute, zoomLevel, rendererInfo, true);
final int bytesEpectedNeeded = tilesNeeded.size() * rendererInfo.getTileSource().getTileSizePixels() * 71;
final String formattedFileSize = FileSizeFormatter.formatFileSize(bytesEpectedNeeded);
new AlertDialog.Builder(this)
.setTitle(R.string.dlg_preloader_title)
.setMessage(String.format(getString(R.string.dlg_preloader_message), tilesNeeded.size(), formattedFileSize))
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener(){
@Override
public void onClick(final DialogInterface d, final int which) {
d.dismiss();
final String progressMessage = getString(R.string.pdg_preloader_message);
final ProgressDialog pd = ProgressDialog.show(OpenStreetDDMap.this, getString(R.string.pdg_preloader_title), String.format(progressMessage,0,tilesNeeded.size()), true, true);
final OSMMapTilePreloader preloader = new OSMMapTilePreloader(OpenStreetDDMap.this, rendererInfo.getTileSource(), tilesNeeded);
preloader.setHandler(new Handler(){
@Override
public void handleMessage(Message msg) {
int progress = preloader.getProgress();
int total = preloader.getTotal();
if(progress < total)
pd.setMessage(String.format(progressMessage, progress, total));
else
pd.dismiss();
}
});
new Thread(preloader).start();
if(OpenStreetDDMap.this.mAutoZoomEnabled){
OpenStreetDDMap.this.mAutoZoomEnabled = false;
Preferences.saveAutoZoomEnabled(OpenStreetDDMap.this, false);
Toast.makeText(OpenStreetDDMap.this, R.string.ddmap_info_preloader_autozoom_disabled, Toast.LENGTH_LONG).show();
}
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener(){
@Override
public void onClick(final DialogInterface d, final int which) {
d.dismiss();
}
}).show();
}
/**
* Starts the SDMainChoose-Activity for result with MODE_SD = MODE_SD_WAYPOINT and the requestcode REQUESTCODE_SD_WAYPOINT.
*/
private void startWaypointActivity() {
final Intent sdIntent = new Intent(this, SDMainChoose.class);
final Bundle b = new Bundle();
b.putInt(MODE_SD, MODE_SD_WAYPOINT);
sdIntent.putExtras(b);
startActivityForResult(sdIntent, REQUESTCODE_SD_WAYPOINT);
}
@Override
public boolean onContextItemSelected(final MenuItem aItem) {
/* Switch on the ID of the item, to get what the user selected. */
switch (aItem.getItemId()) {
case CONTEXTMENU_ADDASWAYPOINT:
this.mWayPoints.add(this.mGPLastMapClick);
// will cause a Route-Refetch
this.kickOffRouteFetch();
return true;
case CONTEXTMENU_CLEARWAYPOINTS:
this.mWayPoints.clear();
// will cause a Route-Refetch
this.kickOffRouteFetch();
return true;
}
return false;
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUESTCODE_ROUTINGFLAGS:
if (resultCode == SUBACTIVITY_RESULTCODE_CHAINCLOSE_SUCCESS || resultCode == SUBACTIVITY_RESULTCODE_SUCCESS) {
initDrivingDirections(INITDRIVINGDIRECTIONS_NEWROUTE);
}else if (resultCode == SUBACTIVITY_RESULTCODE_CHAINCLOSE_QUITTED) {
this.setResult(SUBACTIVITY_RESULTCODE_UP_ONE_LEVEL);
this.finish();
}
break;
case REQUESTCODE_SETTINGS:
final int displayQuality = Preferences.getDisplayQuality(this);
final DirectionArrowDescriptor pDirectionArrowDescriptor = Preferences.getHUDImplVariationDirectionArrowDescriptor(this);
/* When returning from the Settings-subActivity, always reset the MapDrivingDirectionsOverlay. */
final OverlayManager overlaymanager = this.mOSMapView.getOverlayManager();
this.mMyMapDrivingDirectionsOverlay.release();
overlaymanager.remove(this.mMyMapDrivingDirectionsOverlay);
this.mMyMapDrivingDirectionsOverlay = new MapDrivingDirectionsOverlay(this, displayQuality, this.mRealtimeNav, pDirectionArrowDescriptor);
overlaymanager.add(this.mMyMapDrivingDirectionsOverlay);
/* Refresh possibly changed UnitSystems. */
this.mHUDImpl.getRemainingSummaryView().setDisplayQuality(displayQuality);
this.mHUDImpl.getNextActionView().setDisplayQuality(displayQuality);
this.mHUDImpl.getUpperNextActionView().setDisplayQuality(displayQuality);
final UnitSystem unitSystem = Preferences.getUnitSystem(this);
this.mHUDImpl.getNextActionView().setUnitSystem(unitSystem);
this.mHUDImpl.getUpperNextActionView().setUnitSystem(unitSystem);
this.mHUDImpl.getRemainingSummaryView().setUnitSystem(unitSystem);
if (Preferences.getUnitSystem(this) == UnitSystem.IMPERIAL) {
this.mScaleIndicatorView.setImperial();
} else {
this.mScaleIndicatorView.setMetric();
}
break;
case REQUESTCODE_SD_WAYPOINT:
if (resultCode == SUBACTIVITY_RESULTCODE_CHAINCLOSE_SUCCESS || resultCode == SUBACTIVITY_RESULTCODE_SUCCESS) {
final Bundle extras = data.getExtras();
GeoPoint via = null;
/* Switch on the Mode. */
final int searchMode = extras.getInt(EXTRAS_MODE);
switch (searchMode) {
case EXTRAS_MODE_DIRECT_LATLNG:
final int latE6 = extras.getInt(EXTRAS_DESTINATION_LATITUDE_ID);
final int lonE6 = extras.getInt(EXTRAS_DESTINATION_LONGITUDE_ID);
via = new GeoPoint(latE6, lonE6);
break;
default:
throw new IllegalArgumentException("Unawaited SEARCHMODE!");
}
if(via == null){
// TODO Show error
} else {
this.mWayPoints.add(via);
this.kickOffRouteFetch();
}
}
break;
}
}
@Override
public void onRouteResumed() {
if(!this.mRealtimeNav) {
return;
}
Log.d(Constants.DEBUGTAG, "Route Resumed.");
this.mOnRouteStatus = ON_ROUTE;
/* Remove any upcoming route-refetches from the Handler. */
this.mRefetchTriggerHandler.removeCallbacks(this.mRefetchRunner);
this.mRouteRefetchRunning = false;
runOnUiThread(new Runnable(){
@Override
public void run() {
if (OpenStreetDDMap.this.mDirectionVoiceEnabled) {
OpenStreetDDMap.this.mSoundManager.playSound(R.raw.route_resumed);
}
OpenStreetDDMap.this.mIvRouteStatus.setVisibility(View.GONE);
}
});
}
@Override
public void onRouteMissed() {
if(!this.mRealtimeNav) {
return;
}
this.mOnRouteStatus = OFF_ROUTE;
runOnUiThread(new Runnable(){
@Override
public void run() {
if (OpenStreetDDMap.this.mDirectionVoiceEnabled) {
OpenStreetDDMap.this.mSoundManager.playSound(R.raw.route_missed);
}
OpenStreetDDMap.this.mIvRouteStatus.setImageDrawable(OpenStreetDDMap.this.mOffRouteDrawable);
OpenStreetDDMap.this.mIvRouteStatus.setVisibility(View.VISIBLE);
}
});
if (!this.mRouteRefetchRunning) {
this.mRouteRefetchRunning = true;
Log.d(Constants.DEBUGTAG, "Refetching Route in 8 seconds...");
this.mRefetchTriggerHandler.postDelayed(this.mRefetchRunner, this.TIME_BETWEEN_MISS_REFETCH);
} else {
Log.d(Constants.DEBUGTAG, "No refetch, because: this.mRouteRefetchRunning == true");
}
}
@Override
public void onTargetReached() {
if(!this.mRealtimeNav) {
return;
}
runOnUiThread(new Runnable() {
@Override
public void run() {
if(OpenStreetDDMap.this.mDirectionVoiceEnabled) {
OpenStreetDDMap.this.mSoundManager.playSound(R.raw.target_reached);
}
Toast.makeText(OpenStreetDDMap.this, R.string.ddmap_info_target_reached, Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onWaypointPassed(final List<GeoPoint> waypointsLeft) {
if(!this.mRealtimeNav) {
return;
}
/** Clear old waypoints and add the new ones passed by the Navigator. */
this.mWayPoints.clear();
for (final GeoPoint gp : waypointsLeft) {
this.mWayPoints.add(gp);
}
runOnUiThread(new Runnable() {
@Override
public void run() {
if(OpenStreetDDMap.this.mDirectionVoiceEnabled) {
OpenStreetDDMap.this.mSoundManager.playSound(R.raw.waypoint_passed);
}
Toast.makeText(OpenStreetDDMap.this, R.string.ddmap_info_waypoint_passed, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onReceiveAudibleTurnCommand(final AudibleTurnCommand pATC) {
if(!this.mRealtimeNav) {
return;
}
/*
* No need to check: if(this.mDirectionVoiceEnabled) as in that case we
* are not registering ourself as a listener.
*/
if (this.mOnRouteStatus != ON_ROUTE) {
return;
}
final UnitSystem us = Preferences.getUnitSystem(this);
runOnUiThread(new Runnable() {
@Override
public void run() {
final DistanceVoiceElement dve = pATC.getDistanceVoiceElement();
final TurnVoiceElement tve = pATC.getTurnVoiceElement();
final Integer voiceType = OpenStreetDDMap.this.mTurnVoiceSayList.get(dve.LENGTH_METERS);
if(voiceType != null){
int voiceTypeIntValue = voiceType.intValue();
/* If TTS is not (yet) available, fallback to non-tts speech. */
if(OpenStreetDDMap.this.mTTSAvailable == false){
switch(voiceTypeIntValue){
case PreferenceConstants.PREF_TURNVOICESAYLIST_SPEECH_DISTANCE:
voiceTypeIntValue = PreferenceConstants.PREF_TURNVOICESAYLIST_SAY_DISTANCE;
break;
case PreferenceConstants.PREF_TURNVOICESAYLIST_SPEECH_TURN:
voiceTypeIntValue = PreferenceConstants.PREF_TURNVOICESAYLIST_SAY_TURN;
break;
case PreferenceConstants.PREF_TURNVOICESAYLIST_SPEECH_DISTANCE_AND_TURN:
voiceTypeIntValue = PreferenceConstants.PREF_TURNVOICESAYLIST_SAY_DISTANCE_AND_TURN;
break;
}
}
/* Gets set on demand. */
final String fullTurnTextImproved;
final String distanceString = "In " + dve.LENGTH_UNITWISE + " " + dve.getUnitTextual(OpenStreetDDMap.this, OpenStreetDDMap.this.mDrivingDirectionsLanguage);
final String thenString;
if(pATC.hasThenCommand()){
final SimpleAudibleTurnCommand satc = pATC.getThenCommand();
final DistanceVoiceElement thenDVE = satc.getDistanceVoiceElement();
final TurnVoiceElement thenTVE = satc.getTurnVoiceElement();
final String tveText = thenTVE.getText(OpenStreetDDMap.this, OpenStreetDDMap.this.mDrivingDirectionsLanguage);
if(thenDVE == null){
final String thenStringRaw = OpenStreetDDMap.this.mDrivingDirectionsLanguage.getThenCommandWithoutDistance(OpenStreetDDMap.this, RoutePreferenceType.FASTEST); // TODO get RoutePreferenceType from bundle
thenString = ". " + thenStringRaw.replace("%s", tveText);
}else{
final UnitSystem us = Preferences.getUnitSystem(OpenStreetDDMap.this);
final String thenStringRaw = OpenStreetDDMap.this.mDrivingDirectionsLanguage.getThenCommandWithDistance(OpenStreetDDMap.this, RoutePreferenceType.FASTEST); // TODO get RoutePreferenceType from bundle
final String[] distanceStringFull = us.getDistanceStringFull(OpenStreetDDMap.this, OpenStreetDDMap.this.mDrivingDirectionsLanguage, null, thenDVE.LENGTH_UNITWISE);
thenString = ". " + thenStringRaw.replace("%d", "" + thenDVE.LENGTH_UNITWISE + " " + distanceStringFull[UnitSystem.DISTSTRINGS_UNIT_ID]).replace("%s", tveText);
}
}else{
thenString = "";
}
switch(voiceTypeIntValue){
case PreferenceConstants.PREF_TURNVOICESAYLIST_SAY_DISTANCE:
OpenStreetDDMap.this.mSoundManager.playSound(us.convertFromMetricDistanceVoice(dve).RESID);
break;
case PreferenceConstants.PREF_TURNVOICESAYLIST_SAY_TURN:
OpenStreetDDMap.this.mSoundManager.playSound(tve.VOICERESID);
break;
case PreferenceConstants.PREF_TURNVOICESAYLIST_SAY_DISTANCE_AND_TURN:
OpenStreetDDMap.this.mSoundManager.playFollowUpSounds(us.convertFromMetricDistanceVoice(dve).RESID, tve.VOICERESID);
break;
case PreferenceConstants.PREF_TURNVOICESAYLIST_SPEECH_DISTANCE:
OpenStreetDDMap.this.mTTS.speak(distanceString + thenString, 0, null);
break;
case PreferenceConstants.PREF_TURNVOICESAYLIST_SPEECH_TURN:
fullTurnTextImproved = SpeechImprover.improve(pATC.getFullTurnText(), OpenStreetDDMap.this.mRouteCountry);
OpenStreetDDMap.this.mTTS.speak(fullTurnTextImproved + thenString, 0, null);
break;
case PreferenceConstants.PREF_TURNVOICESAYLIST_SPEECH_DISTANCE_AND_TURN:
fullTurnTextImproved = SpeechImprover.improve(pATC.getFullTurnText(), OpenStreetDDMap.this.mRouteCountry);
OpenStreetDDMap.this.mTTS.speak(distanceString + ". " + fullTurnTextImproved + thenString, 0, null);
break;
case PreferenceConstants.PREF_TURNVOICESAYLIST_SAY_NOTHING:
return;
default:
throw new IllegalArgumentException("Default branch in onReceiveAudibleTurnCommand()");
}
}
}
});
}
@Override
protected void onPause() {
Log.d(Constants.DEBUGTAG, "OnPAUSE");
super.onPause();
}
/**
* Load all the settings, that could have changed.
*/
@Override
protected void onResume() {
super.onResume();
final boolean realtimeNavBeforeResume = this.mRealtimeNav;
this.mRealtimeNav = Preferences.getRealTimeNav(this);
if(realtimeNavBeforeResume != this.mRealtimeNav) {
initDrivingDirections(INITDRIVINGDIRECTIONS_NEWROUTE);
}
Log.d(Constants.DEBUGTAG, "OnRESUME");
this.mRouteRefetchRunning = false;
this.mNavigator.forceOffRouteListenerUpdateInNextTick();
this.mCenterMode = Preferences.getCenterMode(this);
this.mRotateMode = Preferences.getRotateMode(this);
this.mSnapToRouteEnabled = Preferences.getSnapToRoute(this);
this.mSnapToRouteRadius = Preferences.getSnapToRouteRadius(this);
NavAlgorithm.setDISTANCE_TO_TOGGLE_OFF_ROUTE(this.mSnapToRouteRadius);
this.mAutoZoomEnabled = Preferences.getAutoZoomEnabled(this);
this.mDirectionVoiceEnabled = Preferences.getDirectionVoiceEnabled(this);
this.mStatisticsEnabled = Preferences.getStatisticsEnabled(this);
this.mDrivingDirectionsLanguage = Preferences.getDrivingDirectionsLanguage(this);
if(this.mRouteCountry == null) {
this.mRouteCountry = this.mDrivingDirectionsLanguage.getMotherCountry();
}
final UnitSystem unitSystem = Preferences.getUnitSystem(this);
if(this.mStatisticsEnabled) {
this.mStatisticsManager = new StatisticsManager(this, unitSystem, Preferences.getStatisticsSessionStart(this));
} else{
this.mStatisticsManager = null;
}
if (this.mRealtimeNav && this.mDirectionVoiceEnabled){
this.mTurnVoiceSayList = Preferences.getTurnVoiceSayList(this);
this.mNavigator.setUnitSystem(unitSystem);
this.mNavigator.setDistanceVoiceCommandListener(this);
}
this.mMyMapDrivingDirectionsOverlay.setRealtimeNav(this.mRealtimeNav);
this.mMyMapDrivingDirectionsOverlay.setMapRotationDegree(Constants.NOT_SET);
((this.mMapRotateView)).setRotationDegree(Constants.NOT_SET);
}
@Override
protected void onRestoreInstanceState(final Bundle inState) {
super.onRestoreInstanceState(inState);
this.mWayPoints = inState.getParcelableArrayList(STATE_WAYPOINTS_ID);
this.mStaticNavCurrentTurnIndex = inState.getInt(STATE_STATICNAVCURRENT_ID);
this.mStaticNavNextTurnIndex = inState.getInt(STATE_STATICNAVNEXT_ID);
this.mDoAutomaticRouteRefetch = inState.getBoolean(STATE_DOAUTOMATICROUTEREFETCH_ID);
this.mInitialRouteFetch = inState.getBoolean(STATE_INITIALROUTEFETCH_ID);
this.mRoute = (Route)inState.getParcelable(STATE_ROUTE_ID);
this.mLastWorkingRoute = (Route)inState.getParcelable(STATE_LASTWORKINGROUTE_ID);
initStaticNavControlsIfNeccessary();
initDrivingDirections(INITDRIVINGDIRECTIONS_RESTORE);
}
@Override
public void onSaveInstanceState(final Bundle outState) {
Log.d(Constants.DEBUGTAG, "OnFREEZE");
outState.putParcelableArrayList(STATE_WAYPOINTS_ID, this.mWayPoints);
outState.putInt(STATE_STATICNAVCURRENT_ID, this.mStaticNavCurrentTurnIndex);
outState.putInt(STATE_STATICNAVNEXT_ID, this.mStaticNavNextTurnIndex);
outState.putBoolean(STATE_DOAUTOMATICROUTEREFETCH_ID, this.mDoAutomaticRouteRefetch);
outState.putBoolean(STATE_INITIALROUTEFETCH_ID, this.mInitialRouteFetch);
outState.putParcelable(STATE_ROUTE_ID, this.mRoute);
outState.putParcelable(STATE_LASTWORKINGROUTE_ID, this.mLastWorkingRoute);
this.mRefetchTriggerHandler.removeCallbacks(this.mRefetchRunner);
if(this.mStatisticsEnabled && this.mStatisticsManager != null) {
this.mStatisticsManager.writeThrough();
}
super.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
Log.d(Constants.DEBUGTAG, "OnDESTROY");
this.mTTS.shutdown();
this.mRefetchTriggerHandler.removeCallbacks(this.mRefetchRunner);
this.mWakeLock.release();
this.mSoundManager.releaseAll();
if(this.mStatisticsManager != null) {
this.mStatisticsManager.finish();
}
super.onDestroy();
}
@Override
public void onLocationLost(final AndNavLocation pLocation) {
// TODO anzeigen...
}
@Override
public void onLocationChanged(final AndNavLocation pLocation) {
if(super.mOSMapView == null) {
return;
}
try{
if(this.mStatisticsEnabled && this.mStatisticsManager != null) {
this.mStatisticsManager.tick(pLocation);
}
/* Advanced Logic to determine, where we are on our route. */
if(this.mNavigator != null) {
this.mNavigator.tick(pLocation);
}
if(!this.mRealtimeNav){
super.mOSMapView.postInvalidate();
return;
}
/* Redraw the whole mapView, which also makes
* our Overlay(s) being redrawn. */
sendRotationToChildren();
refreshTurnText();
refreshHUD();
final long now = System.currentTimeMillis();
if(now > this.mAutoCenterBlockedUntil){
switch(this.mCenterMode) {
case PREF_CENTERMODE_CENTERUSER:
if (this.mNavigator.isReady()) {
zoomAndCenterOnLocation(true);
break;
}
break;
case PREF_CENTERMODE_UPTO_NEXTTURN:
if (this.mNavigator.isReady()) {
zoomAndCenterBetweenLocationAndNextTurn();
break;
}
}
}
super.mOSMapView.postInvalidate();
}catch(final Exception e){
Exceptor.e("Error in onLocationChanged()", e, this);
}
}
private void refreshHUD() {
try{
if(!this.mRealtimeNav){
if(this.mRoute == null || this.mStaticNavCurrentTurnIndex == Constants.NOT_SET){
this.mMapItemControlView.setPreviousEnabled(false);
this.mMapItemControlView.setNextEnabled(false);
this.mMyMapDrivingDirectionsOverlay.setStaticNavCurrentTurnPointIndex(Constants.NOT_SET);
this.mHUDImpl.getNextActionView().reset();
this.mHUDImpl.getRemainingSummaryView().reset();
if(this.mStatisticsManager != null){
this.mHUDImpl.getNextActionView().setCurrentMeterSpeed((int)this.mStatisticsManager.getCurrentSpeed());
this.mHUDImpl.getRemainingSummaryView().setMetersDrivenSession((int)this.mStatisticsManager.getMetersScaleDrivenSession());
}
}else{
final List<RouteInstruction> tps = this.mRoute.getRouteInstructions();
final int tpsSizeLessOne = tps.size() - 1;
final int staticNavCurrentTurnIndex = Math.min(this.mStaticNavCurrentTurnIndex, tpsSizeLessOne);
final int staticNavNextTurnIndex = Math.min(this.mStaticNavNextTurnIndex, tpsSizeLessOne);
this.mMapItemControlView.setPreviousEnabled(staticNavCurrentTurnIndex > 0);
this.mMapItemControlView.setNextEnabled(staticNavNextTurnIndex < tpsSizeLessOne);
this.mMyMapDrivingDirectionsOverlay.setStaticNavCurrentTurnPointIndex(staticNavCurrentTurnIndex);
final RouteInstruction currentTurnPoint = tps.get(staticNavCurrentTurnIndex);
final RouteInstruction nextTurnPoint = tps.get(staticNavNextTurnIndex);
this.mHUDImpl.getNextActionView().setDistance(currentTurnPoint.getLengthMeters());
final int staticNavCurrentTurnIndexInRoute = currentTurnPoint.getFirstMotherPolylineIndex();
this.mHUDImpl.getRemainingSummaryView().setDistance(this.mRoute.getRouteSegmentLengthsUpToDestination()[staticNavCurrentTurnIndexInRoute]);
int dur = 0;
for(int i = tpsSizeLessOne; i >= this.mStaticNavCurrentTurnIndex; i--) {
dur += tps.get(i).getDurationSeconds();
}
this.mHUDImpl.getRemainingSummaryView().setEstimatedRestSeconds(dur);
this.mHUDImpl.getTurnTurnDescriptionView().setTurnDescription(nextTurnPoint.getDescription());
/* ALways show the angle, except on the very last one, show the Flag. */
if(staticNavNextTurnIndex == tpsSizeLessOne){
this.mHUDImpl.getNextActionView().showTargetReached();
this.mHUDImpl.setUpperNextActionViewNecessary(false);
} else if(staticNavNextTurnIndex + 1 == tpsSizeLessOne){
/* The uppernext one is the target. */
this.mHUDImpl.getNextActionView().setTurnAngle(nextTurnPoint.getAngle());
this.mHUDImpl.setUpperNextActionViewNecessary(true);
this.mHUDImpl.getUpperNextActionView().showTargetReached();
}else{
/* Both are visible. */
this.mHUDImpl.getNextActionView().setTurnAngle(nextTurnPoint.getAngle());
final RouteInstruction upperNextTurnPoint = tps.get(staticNavNextTurnIndex + 1);
this.mHUDImpl.setUpperNextActionViewNecessary(true);
this.mHUDImpl.getUpperNextActionView().setTurnAngle(upperNextTurnPoint.getAngle());
this.mHUDImpl.getUpperNextActionView().setDistance(nextTurnPoint.getLengthMeters());
}
}
}else{
final Navigator nav = this.mNavigator; // Drag to local field
if(this.mRoute == null || !nav.isReady()){
this.mHUDImpl.getNextActionView().reset();
this.mHUDImpl.getRemainingSummaryView().reset();
if(this.mStatisticsManager != null){
this.mHUDImpl.getNextActionView().setCurrentMeterSpeed((int)this.mStatisticsManager.getCurrentSpeed());
this.mHUDImpl.getRemainingSummaryView().setMetersDrivenSession((int)this.mStatisticsManager.getMetersScaleDrivenSession());
}
}else{
final List<RouteInstruction> tps = this.mRoute.getRouteInstructions();
final int tpsSizeLessOne = tps.size() - 1;
this.mHUDImpl.getNextActionView().setDistance(nav.getDistanceToNextTurnPoint());
this.mHUDImpl.getRemainingSummaryView().setDistance(nav.getTotalRestDistance());
this.mHUDImpl.getRemainingSummaryView().setEstimatedRestSeconds(nav.getEstimatedRestSeconds());
/* ALways show the angle, except on the very last one, show the Flag. */
final int nextTurnPointIndex = nav.getNextTurnPointIndex();
if(nextTurnPointIndex == tpsSizeLessOne || nextTurnPointIndex == Constants.NOT_SET){
this.mHUDImpl.getNextActionView().showTargetReached();
this.mHUDImpl.setUpperNextActionViewNecessary(false);
} else if(nextTurnPointIndex + 1 == tpsSizeLessOne){
/* The uppernext one is the target. */
this.mHUDImpl.getNextActionView().setTurnAngle(nav.getTurnAngle());
this.mHUDImpl.setUpperNextActionViewNecessary(true);
this.mHUDImpl.getUpperNextActionView().showTargetReached();
}else{
/* Both are visible. */
this.mHUDImpl.getNextActionView().setTurnAngle(nav.getTurnAngle());
this.mHUDImpl.setUpperNextActionViewNecessary(true);
final RouteInstruction nextTurnPoint = tps.get(nextTurnPointIndex);
final RouteInstruction upperNextTurnPoint = tps.get(nextTurnPointIndex + 1);
this.mHUDImpl.getUpperNextActionView().setTurnAngle(upperNextTurnPoint.getAngle());
this.mHUDImpl.getUpperNextActionView().setDistance(nextTurnPoint.getLengthMeters());
}
}
}
if(super.mLocationProvider.hasNumberOfLandmarks()){
this.mHUDImpl.getRemainingSummaryView().setGPSConnectionStrength(super.mLocationProvider.getNumberOfLandmarks());
}else{
this.mHUDImpl.getRemainingSummaryView().setGPSConnectionStrength(0);
}
this.mHUDImpl.invalidateViews();
}catch(final Exception e){
Exceptor.e("HudRefresh-Error", e, this);
}
}
private void refreshTurnText() {
/* Update the textView with the turn-description. */
if(this.mRoute == null || !this.mNavigator.isReady()){
this.mHUDImpl.getTurnTurnDescriptionView().reset();
}else{
final int nextTurnPointIndex = this.mNavigator.getNextTurnPointIndex();
if(nextTurnPointIndex != Constants.NOT_SET && nextTurnPointIndex < this.mRoute.getRouteInstructions().size()) {
this.mHUDImpl.getTurnTurnDescriptionView().setTurnDescription(this.mRoute.getRouteInstructions().get(nextTurnPointIndex).getDescription());
}
}
}
private void zoomAndCenterOnLocation(final boolean animateNotJustCenter) {
/* Drag to local field. */
if(!super.mLocationProvider.hasLastKnownLocation()) {
return;
}
final AndNavLocation lastKnownExcatLocation = super.mLocationProvider.getLastKnownLocation();
/* Just center to the current location. */
if(animateNotJustCenter) {
this.mOSMapView.getController().animateTo(lastKnownExcatLocation, AnimationType.MIDDLEPEAKSPEED);
} else {
super.mOSMapView.getController().setCenter(lastKnownExcatLocation);
}
if(this.mAutoZoomEnabled && this.mNavigator.isReady() && this.mRoute != null && System.currentTimeMillis() > this.mAutoZoomBlockedUntil){
final int nextRoutePoint = this.mNavigator.getNextRoutePointIndex();
if(nextRoutePoint != Constants.NOT_SET){
final int myLatE6 = lastKnownExcatLocation.getLatitudeE6();
final int myLonE6 = lastKnownExcatLocation.getLongitudeE6();
final int newMaxLat = Math.max(myLatE6, this.mRoute.getLatitudeMaxSpan(nextRoutePoint));
final int newMinLat = Math.min(myLatE6, this.mRoute.getLatitudeMinSpan(nextRoutePoint));
final int newMaxLon = Math.max(myLonE6, this.mRoute.getLongitudeMaxSpan(nextRoutePoint));
final int newMinLon = Math.min(myLonE6, this.mRoute.getLongitudeMinSpan(nextRoutePoint));
final int reqLatSpan = (int)(1.2f * (newMaxLat - newMinLat)); // 20% Margin
final int reqLonSpan = (int)(1.2f * (newMaxLon - newMinLon)); // 20% Margin
this.mOSMapView.getController().zoomToSpan(reqLatSpan, reqLonSpan);
}
}
}
private void zoomAndCenterBetweenLocationAndNextTurn() {
if(!this.mNavigator.isReady() || this.mNavigator.getNextTurnPointIndex() == Constants.NOT_SET){
zoomAndCenterOnLocation(true);
}else{
if(super.mLocationProvider.hasLastKnownLocation()){
final GeoPoint nextTurnPoint = this.mNavigator.getNextTurnPointIndexAsGeoPoint();
final int nextRoutePointIndex = this.mNavigator.getNextRoutePointIndex();
if(nextRoutePointIndex != Constants.NOT_SET) {
centerAndZoomBetween(nextRoutePointIndex, super.mLocationProvider.getLastKnownLocation(), nextTurnPoint, true);
}
}
}
}
private void centerAndZoomBetween(final int aRoutePointIndex, final GeoPoint aFirstGP, final GeoPoint pGP, final boolean animateNotJustCenter){
if(aRoutePointIndex == Constants.NOT_SET || pGP == null) {
return;
}
final int myLatE6 = aFirstGP.getLatitudeE6();
final int myLonE6 = aFirstGP.getLongitudeE6();
final int centerLat = (pGP.getLatitudeE6() + myLatE6) >> 1; // ">> 1" == "/ 2"
final int centerLon = (pGP.getLongitudeE6() + myLonE6) >> 1; // ">> 1" == "/ 2"
final GeoPoint newCenter = new GeoPoint(centerLat, centerLon);
if(animateNotJustCenter) {
this.mOSMapView.getController().animateTo(newCenter, AnimationType.MIDDLEPEAKSPEED);
} else {
this.mOSMapView.getController().setCenter(newCenter);
}
final Route route = this.mRoute;
if(this.mAutoZoomEnabled && this.mNavigator.isReady() && route != null && System.currentTimeMillis() > this.mAutoZoomBlockedUntil){
/* Zoom to the middle of the current location and the next turnpoint. */
final int newMaxLat = Math.max(myLatE6, route.getLatitudeMaxSpan(aRoutePointIndex));
final int newMinLat = Math.min(myLatE6, route.getLatitudeMinSpan(aRoutePointIndex));
final int newMaxLon = Math.max(myLonE6, route.getLongitudeMaxSpan(aRoutePointIndex));
final int newMinLon = Math.min(myLonE6, route.getLongitudeMinSpan(aRoutePointIndex));
final int reqLatSpan = (int)(1.2f * (newMaxLat - newMinLat)); // 20% Margin
final int reqLonSpan = (int)(1.2f * (newMaxLon - newMinLon)); // 20% Margin
this.mOSMapView.getController().zoomToSpan(reqLatSpan, reqLonSpan);
}
}
private void sendRotationToChildren() {
if (this.mRotateMode == PREF_ROTATEMODE_DRIVINGDIRECTION_UP && this.mLocationProvider.hasBearing()) {
final float bearing = this.mLocationProvider.getBearing();
this.mMapRotateView.setRotationDegree(bearing);
this.mMyMapDrivingDirectionsOverlay.setMapRotationDegree(bearing); // TODO <-- Neccessary ???
}
}
// ===========================================================
// Methods
// ===========================================================
private void applyViewListeners() {
this.findViewById(R.id.iv_ddmap_zoomin).setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
OpenStreetDDMap.super.mOSMapView.getController().zoomIn();
OpenStreetDDMap.super.mOSMapView.invalidate();
OpenStreetDDMap.this.mAutoZoomBlockedUntil = System.currentTimeMillis() + AUTOZOOM_BLOCKTIME;
}
});
this.findViewById(R.id.iv_ddmap_zoomout).setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
OpenStreetDDMap.super.mOSMapView.getController().zoomOut();
OpenStreetDDMap.super.mOSMapView.invalidate();
OpenStreetDDMap.this.mAutoZoomBlockedUntil = System.currentTimeMillis() + AUTOZOOM_BLOCKTIME;
}
});
this.mHUDImpl.getRemainingSummaryView().setRemainingSummaryOnClickListener(new OnClickListener(){
@Override
public void onClick(final View v) {
OpenStreetDDMap.this.mHUDImpl.getRemainingSummaryView().onClick();
}
});
final OnClickListener speakTurnOnClickListener = new OnClickListener(){
@Override
public void onClick(final View v) {
speakTurn();
}
};
this.mHUDImpl.getNextActionView().setNextActionOnClickListener(speakTurnOnClickListener);
this.mHUDImpl.getUpperNextActionView().setNextActionOnClickListener(speakTurnOnClickListener);
this.mHUDImpl.getTurnTurnDescriptionView().setTurnDescriptionOnClickListener(speakTurnOnClickListener);
}
/** Speaks out the next turn via TTS (If Navigator is ready). */
private void speakTurn() {
final String turnDescription = this.mHUDImpl.getTurnTurnDescriptionView().getTurnDescription().toString();
if(OpenStreetDDMap.this.mNavigator.isReady() && turnDescription != null && turnDescription.length() > 0){
final UnitSystem us = Preferences.getUnitSystem(OpenStreetDDMap.this);
final String[] lengthAndUnit;
if(OpenStreetDDMap.this.mRealtimeNav){
lengthAndUnit = us.getDistanceStringFull(OpenStreetDDMap.this, this.mDrivingDirectionsLanguage, null, OpenStreetDDMap.this.mNavigator.getDistanceToNextTurnPoint());
}else{ /* Static Navigation. */
final RouteInstruction nextInstruction = OpenStreetDDMap.this.mRoute.getRouteInstructions().get(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex);
lengthAndUnit = us.getDistanceStringFull(OpenStreetDDMap.this, this.mDrivingDirectionsLanguage, null, nextInstruction.getLengthMeters());
}
final String textToSay = "In " + lengthAndUnit[UnitSystem.DISTSTRINGS_DIST_ID] + " " + lengthAndUnit[UnitSystem.DISTSTRINGS_UNIT_ID] + ", " + turnDescription;
OpenStreetDDMap.this.mTTS.speak(SpeechImprover.improve(textToSay, OpenStreetDDMap.this.mRouteCountry), 0, null);
}
}
@Override
public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) {
menu.setHeaderTitle("ContextMenu");
menu.add(0, CONTEXTMENU_ADDASWAYPOINT, Menu.NONE, R.string.maps_contextmenu_add_as_waypoint).setIcon(R.drawable.wipe);
menu.add(1, CONTEXTMENU_CLEARWAYPOINTS, Menu.NONE, R.string.maps_contextmenu_clear_waypoints).setIcon(R.drawable.optimize);
menu.add(2, CONTEXTMENU_CLOSE, Menu.NONE, R.string.maps_contextmenu_add_as_waypoint).setIcon(R.drawable.close);
/* Add as many context-menu-options as you want to. */
}
private void applyMapViewLongPressListener() {
final GestureDetector gd = new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
@Override
public void onLongPress(final MotionEvent e) {
final Projection pj = OpenStreetDDMap.super.mOSMapView.getProjection();
OpenStreetDDMap.this.mGPLastMapClick = pj.fromPixels((int)e.getX(), (int)e.getY());
final String[] items = new String[]{getString(R.string.ddmap_contextmenu_add_as_waypoint),
getString(R.string.ddmap_contextmenu_add_as_avoidarea),
getString(R.string.ddmap_contextmenu_clear_waypoints),
getString(R.string.ddmap_contextmenu_clear_avoidareas),
getString(R.string.ddmap_contextmenu_close),
getString(R.string.ddmap_contextmenu_exit)};
new AlertDialog.Builder(OpenStreetDDMap.this)
.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener(){
@Override
public void onClick(final DialogInterface d, final int which) {
d.dismiss();
switch(which){
case 0:
OpenStreetDDMap.this.mWayPoints.add(OpenStreetDDMap.this.mGPLastMapClick);
/* Cause a Route-Refetch. */
OpenStreetDDMap.this.kickOffRouteFetch();
break;
case 1:
final UnitSystem us = Preferences.getUnitSystem(OpenStreetDDMap.this);
final int[] valDist;
switch(us){
case IMPERIAL:
valDist = getResources().getIntArray(R.array.poi_avoidarea_radius_ors_imperial);
break;
case METRIC:
default:
valDist = getResources().getIntArray(R.array.poi_avoidarea_radius_ors_metric);
}
final String[] valStr = new String[valDist.length];
for (int i = 0; i < valDist.length; i++){
final int cur = valDist[i];
if(cur == SDPOISearchList.POISEARCH_RADIUS_GLOBAL){
valStr[i] = getString(R.string.poi_search_radius_global);
}else{
final String[] distStringParts = us.getDistanceString(cur, null);
valStr[i] = distStringParts[UnitSystem.DISTSTRINGS_DIST_ID] + distStringParts[UnitSystem.DISTSTRINGS_UNIT_ID];
}
}
new AlertDialog.Builder(OpenStreetDDMap.this)
.setTitle(R.string.ddmap_contextmenu_clear_avoidareas_radius_title)
.setSingleChoiceItems(valStr, 0, new DialogInterface.OnClickListener(){
@Override
public void onClick(final DialogInterface d, final int which) {
OpenStreetDDMap.this.mAvoidAreas.add(new CircleByCenterPoint(OpenStreetDDMap.this.mGPLastMapClick, valDist[which]));
/* Cause a Route-Refetch. */
OpenStreetDDMap.this.kickOffRouteFetch();
d.dismiss();
}
})
.create().show();
break;
case 2:
OpenStreetDDMap.this.mWayPoints.clear();
/* Cause a Route-Refetch. */
OpenStreetDDMap.this.kickOffRouteFetch();
break;
case 3:
OpenStreetDDMap.this.mAvoidAreas.clear();
/* Cause a Route-Refetch. */
OpenStreetDDMap.this.kickOffRouteFetch();
break;
case 4:
break;
case 5:
OpenStreetDDMap.this.finish();
break;
}
}
})
.create().show();
}
});
this.mOSMapView.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(final View v, final MotionEvent ev) {
OpenStreetDDMap.this.mAutoCenterBlockedUntil = System.currentTimeMillis() + AUTOCENTER_BLOCKTIME;
return gd.onTouchEvent(ev);
}
});
}
/**
* Calls <code>kickOffRouteFetch(null, INITDRIVINGDIRECTIONS_NEWROUTE);</code>
*/
private void kickOffRouteFetch() {
kickOffRouteFetch(null, false);
}
/**
* Calls <code>kickOffRouteFetch(null, pRestore);</code>
*/
private void kickOffRouteFetch(final boolean pRestore) {
kickOffRouteFetch(null, pRestore);
}
/**
* Calls <code>kickOffRouteFetch(pGPUseAsStart, INITDRIVINGDIRECTIONS_NEWROUTE);</code>
*/
private void kickOffRouteFetch(final GeoPoint pGPUseAsStart) {
kickOffRouteFetch(pGPUseAsStart, INITDRIVINGDIRECTIONS_NEWROUTE);
}
/**
*
* @param pGPUseAsStart
* @param pRestore passing <code>true</code> will cause the
*/
private void kickOffRouteFetch(final GeoPoint pGPUseAsStart, final boolean pRestore) {
try {
final String dialogMessage;
if (this.mInitialRouteFetch) {
// Display an indeterminate Progress-Dialog
dialogMessage = getString(R.string.pdg_fetchroute_messagestart) + '\n' + getDialogMessage();
} else {
dialogMessage = getString(R.string.please_wait_a_moment);
}
// Display an indeterminate Progress-Dialog
this.mRouteFetchProgressDialog = ProgressDialog.show(OpenStreetDDMap.this,
getString(R.string.pdg_refetchroute_title),
dialogMessage,
true,
true,
new OnCancelListener(){
@Override
public void onCancel(final DialogInterface dialog) {
OpenStreetDDMap.this.finish();
}
});
this.mStaticNavCurrentTurnIndex = Constants.NOT_SET;
this.mStaticNavNextTurnIndex = Constants.NOT_SET;
this.mNavigator.setReady(false);
/* Next Nav-Tick will trigger it back to ON or OFF Route. */
OpenStreetDDMap.this.mOnRouteStatus = REFETCHING_ROUTE;
new Thread(new Runnable() {
@Override
public void run() {
boolean doRetry = true;
int count = 0;
if(OpenStreetDDMap.this.mRoute != null) {
OpenStreetDDMap.this.mLastWorkingRoute = OpenStreetDDMap.this.mRoute;
}
do {
if(pGPUseAsStart != null){
OpenStreetDDMap.this.mGPStart = pGPUseAsStart;
}else{
OpenStreetDDMap.this.setProgressDialogTitle(R.string.pdg_refetchroute_title);
ensureOwnGPSPosition();
if(OpenStreetDDMap.this.mLocationProvider.hasLastKnownLocation()){
OpenStreetDDMap.this.mGPStart = OpenStreetDDMap.this.mLocationProvider.getLastKnownLocation();
}else{
askRetryForReason(R.string.ddmap_info_gps_fetch_tries_exceeded_title, R.string.ddmap_info_gps_fetch_tries_exceeded_message);
return;
}
}
if(pRestore){
OpenStreetDDMap.this.setProgressDialogTitle(R.string.pdg_restoreroute_title);
}else{
if(OpenStreetDDMap.this.mInitialRouteFetch) {
OpenStreetDDMap.this.setProgressDialogTitle(R.string.pdg_fetchroute_title);
} else {
OpenStreetDDMap.this.setProgressDialogTitle(R.string.pdg_refetchroute_title);
}
}
// if (OpenStreetDDMap.this.mDataConnectionStrength == 0) { // TODO Muss wohl raus wegen WiFi!
// askRetryForReason(R.string.ddmap_info_route_fetch_no_dataconnection_title, R.string.ddmap_info_route_fetch_no_dataconnection_message);
// return;
// }
/* Use our own GPS-Position */
Route aRoute = null;
try {
if(pRestore){
aRoute = OpenStreetDDMap.this.mRoute;
}else{
Log.d(Constants.DEBUGTAG, "BEFORE Creating ROute");
aRoute = createRouteFromBundleCreatedWith();
Log.d(Constants.DEBUGTAG, "AFTER Creating ROute");
}
/* No Exception, no need to retry. */
doRetry = false;
} catch (final ORSException nrfe) {
Log.d(Constants.DEBUGTAG, "ERROR Creating ROute");
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OpenStreetDDMap.this, nrfe.getErrors().get(0).toString(), Toast.LENGTH_SHORT).show();
}
});
doRetry = true;
Log.e(Constants.DEBUGTAG, "No Route found.");
} catch (final UnknownHostException uhe) {
askRetryForReason(R.string.ddmap_info_route_fetch_no_dataconnection_title, R.string.ddmap_info_route_fetch_no_dataconnection_message);
return;
} catch (final Exception e) {
doRetry = true;
Log.e(Constants.DEBUGTAG, "Route-Fetch-Error.", e);
}
if(OpenStreetDDMap.this.mGPStartInitial == null) {
OpenStreetDDMap.this.mGPStartInitial = OpenStreetDDMap.this.mGPStart;
}
OpenStreetDDMap.this.mRoute = aRoute;
if (doRetry){
count++;
if(count >= MAPFETCH_TRIES_TO_GET_ROUTE) {
if(OpenStreetDDMap.this.mBundleCreatedWith.getString(EXTRAS_STREETNUMBER_ID) != null) {
askToTryWithoutStreetnumber();
} else {
askRetryForReason(R.string.ddmap_info_route_fetch_tries_exceeded_title, R.string.ddmap_info_route_fetch_tries_exceeded_message);
}
return;
}
}
} while (doRetry);
OpenStreetDDMap.this.mLastWorkingWayPoints = org.androad.util.Util.cloneDeep(OpenStreetDDMap.this.mWayPoints);
Log.d(Constants.DEBUGTAG, "Route Found!");
/* Route was found... */
runOnUiThread(new Runnable() {
@Override
public void run() {
initNavigationOnRoute(OpenStreetDDMap.this.mRoute, pRestore);
}
});
}
/**
* Opens an AlterDialog,
* which asks the user if he wants to try searching the route,
* without the streetnumber he entered.
* If he presses <code>YES</code>, the streetNumber gets deleted from the
* <code>mBundleCreatedWith</code> and the Route-ReFetch gets kicked of again.
* If he presses <code>NO</code> this Activity gets finished.
*/
private void askToTryWithoutStreetnumber(){
runOnUiThread(new Runnable() {
@Override
public void run() {
try{
OpenStreetDDMap.this.mRouteFetchProgressDialog.dismiss();
final AlertDialog.Builder ab = new AlertDialog.Builder(OpenStreetDDMap.this)
.setTitle(R.string.ddmap_info_route_fetch_tries_exceeded_ask_remove_streetnumber_title)
.setIcon(R.drawable.face_sad)
.setMessage(R.string.ddmap_info_route_fetch_tries_exceeded_ask_remove_streetnumber_message)
.setPositiveButton(R.string.yes_UPPERCASE, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface arg0, final int arg1) {
OpenStreetDDMap.this.mBundleCreatedWith.remove(EXTRAS_STREETNUMBER_ID);
OpenStreetDDMap.this.kickOffRouteFetch();
}
})
.setNegativeButton(R.string.no_UPPERCASE, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface arg0, final int arg1) {
OpenStreetDDMap.this.finish();
}
});
if(OpenStreetDDMap.this.mLastWorkingRoute != null){
ab.setNeutralButton(R.string.ddmap_info_route_fetch_useold, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface arg0, final int arg1) {
OpenStreetDDMap.this.mDoAutomaticRouteRefetch = false;
OpenStreetDDMap.this.mRoute = OpenStreetDDMap.this.mLastWorkingRoute;
OpenStreetDDMap.this.mWayPoints = OpenStreetDDMap.this.mLastWorkingWayPoints;
initNavigationOnRoute(OpenStreetDDMap.this.mRoute, INITDRIVINGDIRECTIONS_NEWROUTE);
}
});
}
ab.create().show();
}catch(final IllegalArgumentException iae){
// Thrown when dismiss is called and activity is already been destroyed
// Log.e(DEBUGTAG, "Error", iae);
}catch(final BadTokenException btw){
// Thrown when create/show is called and activity is already been destroyed
// Log.e(DEBUGTAG, "Error", iae);
}
}
});
}
/**
* Opens an AlterDialog,
* which asks the user if he wants to retry searching for the route,
* without message and title passed as parameters.
* If he presses <code>YES</code> the Route-ReFetch gets kicked of again.
* If he presses <code>NO</code> this Activity gets finished.
* @param aTitleResID
* @param aMessageResID
*/
private void askRetryForReason(final int aTitleResID, final int aMessageResID) {
runOnUiThread(new Runnable() {
@Override
public void run() {
try{
OpenStreetDDMap.this.mRouteFetchProgressDialog.dismiss();
final AlertDialog.Builder ab = new AlertDialog.Builder(OpenStreetDDMap.this)
.setTitle(aTitleResID)
.setIcon(R.drawable.face_sad)
.setMessage(aMessageResID)
.setPositiveButton(R.string.yes_UPPERCASE, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface arg0, final int arg1) {
OpenStreetDDMap.this.kickOffRouteFetch();
}
})
.setNegativeButton(R.string.no_UPPERCASE, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface arg0, final int arg1) {
OpenStreetDDMap.this.finish();
}
});
if(OpenStreetDDMap.this.mLastWorkingRoute != null){
ab.setNeutralButton(R.string.ddmap_info_route_fetch_useold, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface arg0, final int arg1) {
OpenStreetDDMap.this.mDoAutomaticRouteRefetch = false;
OpenStreetDDMap.this.mRoute = OpenStreetDDMap.this.mLastWorkingRoute;
OpenStreetDDMap.this.mWayPoints = OpenStreetDDMap.this.mLastWorkingWayPoints;
initNavigationOnRoute(OpenStreetDDMap.this.mRoute, INITDRIVINGDIRECTIONS_NEWROUTE);
}
});
}
ab.create().show();
}catch(final IllegalArgumentException iae){
// Thrown when dismiss is called and activity is already been destroyed
// Log.e(DEBUGTAG, "Error", iae);
}catch(final BadTokenException btw){
// Thrown when create/show is called and activity is already been destroyed
// Log.e(DEBUGTAG, "Error", iae);
}
}
});
}
}, "RouteFetch-Thread").start();
} catch(final BadTokenException bte){
// Happens somewhen in AdProgressView.show();
}catch (final Exception e) {
Exceptor.e("Routefetch Error", e, this);
// Log.e(Constants.DEBUGTAG, "Exception in kickOffRouteFetch();", e);
}
}
private void ensureOwnGPSPosition() {
int tryCount = MAPFETCH_TRIES_TO_GET_GPS;
do{
tryCount--;
/* Refresh own GPS position. */
if(!OpenStreetDDMap.this.mLocationProvider.hasLastKnownLocation()){
/* Wait until WPS did the job... */
try {
Thread.sleep(200);
} catch (final InterruptedException e) { }
}
}while(!OpenStreetDDMap.this.mLocationProvider.hasLastKnownLocation() && tryCount >= 0);
}
/**
* Initializes the Navigator to work on the Route passed as parameter.<br/>
* The <code>mNavigator</code> field will be working on that Route.
* @param aRoute
* @param
*/
private void initNavigationOnRoute(final Route aRoute, final boolean pRestore) {
this.mRoute = aRoute;
try{
this.findViewById(R.id.iv_ddmap_logo_osm).setVisibility(View.GONE);
this.refreshHUD();
if (this.mRoute != null) {
if(!pRestore){
this.mStaticNavCurrentTurnIndex = 0;
this.mStaticNavNextTurnIndex = 1;
}
this.mNavigator.setRoute(this.mRoute);
this.mNavigator.setReady(true);
this.mRouteRefetchRunning = false;
this.mNavigator.forceOffRouteListenerUpdateInNextTick();
this.mNavigator.tick(super.mLocationProvider.getLastKnownLocation());
this.mOSMapView.postInvalidate();
if (this.mInitialRouteFetch || pRestore) {
this.mInitialRouteFetch = false;
final BoundingBoxE6 bb = this.mRoute.getBoundingBoxE6();
this.mOSMapView.getController().zoomToSpan(bb);
this.mOSMapView.getController().setCenter(this.getLastKnownLocationAsGeoPoint(true));
}
this.mOSMapView.postInvalidate();
this.refreshHUD();
if(this.mRouteFetchProgressDialog != null){
/* The check is needed, because when the Route was
* restored due to a change of the ScreenOrientation,
* there was no ProgressDialog created. */
try{
OpenStreetDDMap.this.mRouteFetchProgressDialog.dismiss();
}catch(final IllegalArgumentException iae){ /* Nothing. */ }
}
}
}catch(final Exception e){
// Thrown when dismiss is called and activity is already been destroyed
Exceptor.e("Error", e, OpenStreetDDMap.this);
}
}
/**
* Blocking method, which returns the Route based on <code>mBundleCreatedWith</code>.
* Also saves the route to SD-Card, if its the initial call and when the user saved the specific setting to the preferences.
* @return the Route
* @throws ORSException
* @throws IOException
* @throws IllegalArgumentException
* @throws SAXException
* @throws Exception
*/
private Route createRouteFromBundleCreatedWith() throws ORSException, IOException, IllegalArgumentException, SAXException, Exception{
final int searchMode = OpenStreetDDMap.this.mBundleCreatedWith.getInt(EXTRAS_MODE);
final boolean saveRouteToSDCard = OpenStreetDDMap.this.mInitialRouteFetch && Preferences.getSaveInitialRoute(this);
/* Switch on the Mode. */
switch (searchMode) {
case EXTRAS_MODE_LOAD_ROUTE_BY_ROUTEHANDLEID:
final long routeHandleID = this.mBundleCreatedWith.getLong(EXTRAS_ROUTEHANDLEID_ID);
return RouteFactory.create(this, routeHandleID);
case EXTRAS_MODE_LOAD_SAVED_ROUTE:
final String aFileName = this.mBundleCreatedWith.getString(EXTRAS_SAVED_ROUTE_FILENAME_ID);
return RSOfflineLoader.load(this, aFileName);
case EXTRAS_MODE_DIRECT_LATLNG:
if(this.mGPDestination == null){
final int latE6 = this.mBundleCreatedWith.getInt(EXTRAS_DESTINATION_LATITUDE_ID);
final int lonE6 = this.mBundleCreatedWith.getInt(EXTRAS_DESTINATION_LONGITUDE_ID);
this.mGPDestination = new GeoPoint(latE6, lonE6);
}
if(this.mInitialRouteFetch){
this.mWayPoints.clear();
final ArrayList<String> viaStrings = this.mBundleCreatedWith.getStringArrayList(EXTRAS_VIAS_ID);
if(viaStrings != null) {
for (final String v : viaStrings) {
this.mWayPoints.add(GeoPoint.fromIntString(v));
}
}
}
final int startLatE6 = this.mBundleCreatedWith.getInt(EXTRAS_START_LATITUDE_ID);
final int startLonE6 = this.mBundleCreatedWith.getInt(EXTRAS_START_LONGITUDE_ID);
if(startLatE6 == 0 && startLonE6 == 0){
/* No startPoint was passed. */
return RouteFactory.create(this, this.mGPStart, this.mGPDestination, this.mWayPoints, this.mAvoidAreas, saveRouteToSDCard);
}else{
if(this.mGPStartInitial == null){
this.mGPStartInitial = new GeoPoint(startLatE6, startLonE6);
return RouteFactory.create(this, this.mGPStartInitial, this.mGPDestination, this.mWayPoints, this.mAvoidAreas, saveRouteToSDCard);
}else{
return RouteFactory.create(this, this.mGPStart, this.mGPDestination, this.mWayPoints, this.mAvoidAreas, saveRouteToSDCard);
}
}
case EXTRAS_MODE_ZIPSEARCH:
case EXTRAS_MODE_CITYNAMESEARCH:
default:
throw new IllegalStateException("Unknown MODE in initDestination.");
}
}
/**
* Sets the title of the <code>mRouteFetchProgressDialog</code>.
* @param aTitleStringID like <code>R.string.hello_world</code>
*/
private void setProgressDialogTitle(final int aTitleStringID) {
setProgressDialogTitle(getString(aTitleStringID));
}
/**
* Sets the title of the <code>mRouteFetchProgressDialog</code>.
* @param aTitle like <code>"Hello World"</code>
*/
private void setProgressDialogTitle(final String aTitle) {
runOnUiThread(new Runnable(){
@Override
public void run() {
try{
OpenStreetDDMap.this.mRouteFetchProgressDialog.setTitle(aTitle);
}catch(final Exception e){
// Log.e(DEBUGTAG, "Error", e);
}
}
});
}
/**
* Returns a string describing the mode the route was requested. <br/>
* Examples
* <ul><li>"Loading from route: "</li><li>"Latitude: 123.45456\nLongitude: 123.4567"</li><li>"Loadign saved route..."</li></ul>
* @return
*/
private String getDialogMessage() {
final StringBuilder sb = new StringBuilder();
/* Switch on the Mode. */
final int searchMode = OpenStreetDDMap.this.mBundleCreatedWith.getInt(EXTRAS_MODE);
switch (searchMode) {
case EXTRAS_MODE_LOAD_ROUTE_BY_ROUTEHANDLEID:
sb.append(getString(R.string.pdg_fetchroute_loading_routebyhandle, this.mBundleCreatedWith.getLong(EXTRAS_ROUTEHANDLEID_ID)));
break;
case EXTRAS_MODE_LOAD_SAVED_ROUTE:
sb.append(getString(R.string.pdg_fetchroute_loading_saved_route));
break;
case EXTRAS_MODE_DIRECT_LATLNG:
final DecimalFormat df = new DecimalFormat("##0.000000");
sb.append(getString(R.string.latitude));
sb.append(": ");
sb.append(df.format(this.mBundleCreatedWith.getInt(EXTRAS_DESTINATION_LATITUDE_ID) / 1E6));
sb.append('\n');
sb.append(getString(R.string.longitude));
sb.append(": ");
sb.append(df.format(this.mBundleCreatedWith.getInt(EXTRAS_DESTINATION_LONGITUDE_ID) / 1E6));
break;
}
return sb.toString();
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
private class StaticNavOverlayControlView implements ItemizedOverlayControlView.ItemizedOverlayControlViewListener{
@Override
public void onCenter() {
if(OpenStreetDDMap.this.mRoute != null){
final List<RouteInstruction> turnPointsRaw = OpenStreetDDMap.this.mRoute.getRouteInstructions();
if(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex == turnPointsRaw.size() - 1){
OpenStreetDDMap.this.mOSMapView.getController().animateTo(OpenStreetDDMap.this.mRoute.getDestination(), AnimationType.MIDDLEPEAKSPEED);
}else{
OpenStreetDDMap.this.mOSMapView.getController().animateTo(turnPointsRaw.get(OpenStreetDDMap.this.mStaticNavNextTurnIndex).getTurnPoint(), AnimationType.MIDDLEPEAKSPEED);
}
}
OpenStreetDDMap.this.mOSMapView.invalidate();
OpenStreetDDMap.this.refreshHUD();
if(OpenStreetDDMap.this.mDirectionVoiceEnabled){
final String turnDescription = OpenStreetDDMap.this.mRoute.getRouteInstructions().get(OpenStreetDDMap.this.mStaticNavNextTurnIndex).getDescription();
OpenStreetDDMap.this.mTTS.speak(SpeechImprover.improve(turnDescription, OpenStreetDDMap.this.mRouteCountry), 0, null);
}
}
@Override
public void onNavTo() {
// Nothing, is disabled so it will never happen.
}
@Override
public void onNext() {
if(OpenStreetDDMap.this.mRoute != null){
final List<RouteInstruction> turnPointsRaw = OpenStreetDDMap.this.mRoute.getRouteInstructions();
OpenStreetDDMap.this.mStaticNavCurrentTurnIndex = Math.min(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex + 1, turnPointsRaw.size() - 1);
OpenStreetDDMap.this.mStaticNavNextTurnIndex = Math.min(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex + 1, turnPointsRaw.size() - 1);
if(OpenStreetDDMap.this.mDirectionVoiceEnabled){
final RouteInstruction currentInstruction = OpenStreetDDMap.this.mRoute.getRouteInstructions().get(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex);
final RouteInstruction nextInstruction = OpenStreetDDMap.this.mRoute.getRouteInstructions().get(OpenStreetDDMap.this.mStaticNavNextTurnIndex);
final UnitSystem us = Preferences.getUnitSystem(OpenStreetDDMap.this);
final String[] lengthAndUnit = us.getDistanceStringFull(OpenStreetDDMap.this, OpenStreetDDMap.this.mDrivingDirectionsLanguage, null, currentInstruction.getLengthMeters());
final String turnDescription = "In " + lengthAndUnit[UnitSystem.DISTSTRINGS_DIST_ID] + " " + lengthAndUnit[UnitSystem.DISTSTRINGS_UNIT_ID] + ", " + nextInstruction.getDescription();
OpenStreetDDMap.this.mTTS.speak(SpeechImprover.improve(turnDescription, OpenStreetDDMap.this.mRouteCountry), 0, null);
}
if(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex == turnPointsRaw.size() - 1){
OpenStreetDDMap.this.mOSMapView.getController().animateTo(OpenStreetDDMap.this.mRoute.getDestination(), AnimationType.MIDDLEPEAKSPEED);
}else{
switch(OpenStreetDDMap.this.mCenterMode){
case PREF_CENTERMODE_CENTERUSER:
OpenStreetDDMap.this.mOSMapView.getController().animateTo(turnPointsRaw.get(OpenStreetDDMap.this.mStaticNavNextTurnIndex).getTurnPoint(), AnimationType.MIDDLEPEAKSPEED);
break;
case PREF_CENTERMODE_UPTO_NEXTTURN:
final int curIndex = Math.min(OpenStreetDDMap.this.mRoute.getPolyLine().size() - 1,
turnPointsRaw.get(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex).getFirstMotherPolylineIndex() + 1);
final GeoPoint curTP = turnPointsRaw.get(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex).getTurnPoint();
final GeoPoint nextTP = turnPointsRaw.get(OpenStreetDDMap.this.mStaticNavNextTurnIndex).getTurnPoint();
centerAndZoomBetween(curIndex,curTP, nextTP, true);
break;
}
}
}
OpenStreetDDMap.this.mOSMapView.invalidate();
OpenStreetDDMap.this.refreshHUD();
}
@Override
public void onPrevious() {
if(OpenStreetDDMap.this.mRoute != null){
OpenStreetDDMap.this.mStaticNavCurrentTurnIndex = Math.max(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex - 1, 0);
final List<RouteInstruction> turnPointsRaw = OpenStreetDDMap.this.mRoute.getRouteInstructions();
OpenStreetDDMap.this.mStaticNavNextTurnIndex = Math.min(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex + 1, turnPointsRaw.size() - 1);
switch(OpenStreetDDMap.this.mCenterMode){
case PREF_CENTERMODE_CENTERUSER:
OpenStreetDDMap.this.mOSMapView.getController().animateTo(turnPointsRaw.get(OpenStreetDDMap.this.mStaticNavNextTurnIndex).getTurnPoint(), AnimationType.MIDDLEPEAKSPEED);
break;
case PREF_CENTERMODE_UPTO_NEXTTURN:
final int curIndex = Math.min(OpenStreetDDMap.this.mRoute.getPolyLine().size() - 1,
turnPointsRaw.get(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex).getFirstMotherPolylineIndex() + 1);
final GeoPoint curTP = turnPointsRaw.get(OpenStreetDDMap.this.mStaticNavCurrentTurnIndex).getTurnPoint();
final GeoPoint nextTP = turnPointsRaw.get(OpenStreetDDMap.this.mStaticNavNextTurnIndex).getTurnPoint();
centerAndZoomBetween(curIndex,curTP, nextTP, true);
break;
}
}
OpenStreetDDMap.this.mOSMapView.invalidate();
OpenStreetDDMap.this.refreshHUD();
}
}
}