// Created by plusminus on 00:14:42 - 02.10.2008 package org.androad.osm; import org.osmdroid.contributor.RouteRecorder; import org.osmdroid.util.GeoPoint; import org.osmdroid.views.MapView; import org.osmdroid.views.util.constants.MapViewConstants; import org.androad.adt.AndNavLocation; import org.androad.loc.AbstractAndNavLocationProvider; import org.androad.loc.NetworkFallbackLocationProvider; import org.androad.loc.AbstractAndNavLocationProvider.AndNavLocationCallback; import org.androad.osm.api.traces.TraceManager; import org.androad.osm.api.traces.util.OSMTraceAPIConstants; import org.androad.osm.util.constants.OSMConstants; import org.androad.ui.common.DataStateChangedListener; import org.androad.ui.common.MyDataStateChangedWatcher; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.KeyEvent; import android.view.Window; /** * Baseclass for Activities who want to contribute to the OpenStreetMap Project. * @author Nicolas Gramlich * */ public abstract class OpenStreetMapActivity extends Activity implements DataStateChangedListener, OSMConstants, MapViewConstants, AndNavLocationCallback { // =========================================================== // Constants // =========================================================== public static final String PREF_MAPCENTER_ID = "pref_mapcenter_id"; // =========================================================== // Fields // =========================================================== protected AbstractAndNavLocationProvider mLocationProvider; protected MapView mOSMapView; private RouteRecorder mRouteRecorder = new RouteRecorder(); private boolean mDoGPSRecordingAndContributing; private MyDataStateChangedWatcher mDscw; private final int mDataConnectionStrength = 5; private boolean mTreatVolumeKeysAsZoom = false; /** When the Map-Activity gets stopped, it writes the last location to the preferences. * This location gets remembered in onCreate(). */ private GeoPoint mRememberedMapCenterFromLastSession; // =========================================================== // Constructors // =========================================================== /** * Calls <code>onCreate(final Bundle savedInstanceState, final boolean pDoGPSRecordingAndContributing)</code> with <code>pDoGPSRecordingAndContributing == true</code>.<br/> * That means it automatically contributes to the OpenStreetMap Project in the background. * @param savedInstanceState */ @Override protected void onCreate(final Bundle savedInstanceState) { onCreate(savedInstanceState, true, true); } /** * Called when the activity is first created. Registers LocationListener. * @param savedInstanceState * @param pDoGPSRecordingAndContributing If <code>true</code>, it automatically contributes to the OpenStreetMap Project in the background. * @param pShowTitleBarInMap <code>true</code> if the title bar should remain visible. */ protected void onCreate(final Bundle savedInstanceState, final boolean pDoGPSRecordingAndContributing, final boolean pShowTitleBarInMap) { super.onCreate(savedInstanceState); // this.mLocationProvider = new SkyhookAndNavLocationProvider(this, this); // this.mLocationProvider = new DefaultLocationProvider(this, this); this.mLocationProvider = new NetworkFallbackLocationProvider(this, this); final String gpString = getPreferences(Context.MODE_PRIVATE).getString(PREF_MAPCENTER_ID, null); this.mRememberedMapCenterFromLastSession = (gpString == null) ? null : GeoPoint.fromIntString(gpString); if(pDoGPSRecordingAndContributing) { this.enableDoGPSRecordingAndContributing(); } else { this.disableDoGPSRecordingAndContributing(false); } /* The app-title-bar just takes some pixels away without being useful. */ if(!pShowTitleBarInMap) { this.requestWindowFeature(Window.FEATURE_NO_TITLE); } this.mLocationProvider.onCreate(); } // =========================================================== // Getter & Setter // =========================================================== public RouteRecorder getRouteRecorder() { return this.mRouteRecorder; } /** Offers the Height of the MapView to the Overlay. */ public int getMapViewHeight() { return this.mOSMapView.getHeight(); } /** Offers the Height of the MapView to the Overlay. */ public int getMapViewWidth() { return this.mOSMapView.getWidth(); } /** Offers the current GPS-position to the Overlay. */ public AbstractAndNavLocationProvider getAndNavLocationProvider() { return this.mLocationProvider; } /** Offers the current GPS-position to the Overlay as a mapPoint. * Wraps around the mLocationProvider, adding a */ public GeoPoint getLastKnownLocation(final boolean pUseRemembered) { if(this.mLocationProvider.hasLastKnownLocation()) { return this.mLocationProvider.getLastKnownLocation(); } else if(pUseRemembered) { return this.mRememberedMapCenterFromLastSession; } else { return null; } } public int getDataConnectionStrength(){ return this.mDataConnectionStrength; } /** * Default: FALSE * @param b */ public void setTreatVolumeKeysAsZoom(final boolean b){ this.mTreatVolumeKeysAsZoom = b; } /** * Default: FALSE * @param b */ public boolean isTreatVolumeKeysAsZoom(){ return this.mTreatVolumeKeysAsZoom; } // =========================================================== // Methods from SuperClass/Interfaces // =========================================================== @Override protected void onResume() { super.onResume(); this.mLocationProvider.onResume(); this.onResumeForDataStateChangedListener(); } @Override public void onDataStateChanged(final int strength) { // TODO } protected abstract void onLocationChanged(final AndNavLocation pLocation); protected abstract void onLocationLost(final AndNavLocation pLocation); @Override public void fireLocationChanged(final AndNavLocation pLocation) { if(OpenStreetMapActivity.this.mDoGPSRecordingAndContributing) { OpenStreetMapActivity.this.mRouteRecorder.add(pLocation, MapViewConstants.NOT_SET); if (OpenStreetMapActivity.this.mRouteRecorder.getRecordedGeoPoints().size() > OSMTraceAPIConstants.MAXGEOPOINTS_FOR_OSM_CONTRIBUTION) { TraceManager.contributeAsync(this, this.mRouteRecorder.getRecordedGeoPoints()); } } onLocationChanged(pLocation); } @Override public void fireLocationLost(final AndNavLocation pLocation) { // TODO Vllt neues segment im recorder? onLocationLost(pLocation); } @Override protected void onStop() { super.onStop(); final GeoPoint gp = getLastKnownLocation(true); if(gp != null && Math.abs(gp.getLatitudeE6()) > 100 && Math.abs(gp.getLongitudeE6()) > 100){ getPreferences(Context.MODE_PRIVATE).edit().putString(PREF_MAPCENTER_ID, gp.toString()).commit(); } this.mLocationProvider.onStop(); this.onResumeForDataStateChangedListener(); } /** * Called when activity is destroyed. Unregisters LocationListener. */ @Override protected void onDestroy() { super.onDestroy(); this.mLocationProvider.onDestroy(); if(this.mDoGPSRecordingAndContributing){ TraceManager.contributeAsync(this, this.mRouteRecorder.getRecordedGeoPoints()); } } /** * Release resources, to free memory. * Especially set all references (also static!!) to {@link Context}s and {@link Drawable} null. * {@link Bitmap}s can be recycle()'d. */ protected abstract void release(); /** Make sure to stop the animation when we're no longer on screen, * failing to do so will cause a lot of unnecessary cpu-usage! */ @Override protected void onPause() { this.onPauseForDataStateChangedListener(); super.onPause(); } @Override public void onPauseForDataStateChangedListener() { this.mDscw.unregister(); } @Override public void onResumeForDataStateChangedListener() { /** Initiates the local field <code>dsir</code> a * DataStateChangedWatcher to notify this class * on changes to the Connection-State... */ this.mDscw = new MyDataStateChangedWatcher(this, this); } @Override public boolean onKeyDown(final int keyCode, final KeyEvent event) { switch(keyCode){ case KeyEvent.KEYCODE_VOLUME_DOWN: if(this.mTreatVolumeKeysAsZoom){ this.mOSMapView.getController().zoomIn(); return true; } break; case KeyEvent.KEYCODE_VOLUME_UP: if(this.mTreatVolumeKeysAsZoom){ this.mOSMapView.getController().zoomOut(); return true; } break; case KeyEvent.KEYCODE_I: // Zooming In this.mOSMapView.getController().zoomIn(); return true; case KeyEvent.KEYCODE_O: // Zooming Out this.mOSMapView.getController().zoomOut(); return true; } return super.onKeyDown(keyCode, event); } // =========================================================== // Methods // =========================================================== public void openMenu(){ this.getWindow().openPanel(Window.FEATURE_OPTIONS_PANEL, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)); } public void enableDoGPSRecordingAndContributing(){ /* If already true, return. */ if(this.mDoGPSRecordingAndContributing) { return; } this.mDoGPSRecordingAndContributing = true; } public void disableDoGPSRecordingAndContributing(final boolean pContributdeCurrentRoute){ /* If already false, return. */ if(!this.mDoGPSRecordingAndContributing) { return; } if(pContributdeCurrentRoute){ TraceManager.contributeAsync(this, this.mRouteRecorder.getRecordedGeoPoints()); } /* 'Clear' the recordedGeopoints. * this.mRouteRecorder.getRecordedGeoPoints().clear(); * is not possible, as the previous 'contributeAsync' is asynchronous. */ this.mRouteRecorder = new RouteRecorder(); this.mDoGPSRecordingAndContributing = false; } // =========================================================== // Inner and Anonymous Classes // =========================================================== }