Archiv für Januar 2012

Android Map App Part 3 – The Map Activity

Here we come to the heart of the app: The Map Activity.

I’ll not post the whole code now because it would make it complicated to explain. That’s why i’ll post parts of the code with some comments (the complete code is at the end):


@Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 requestWindowFeature(Window.FEATURE_NO_TITLE);
 setActionBarContentView(R.layout.main);
 getActionBar().setType(ActionBar.Type.Empty);

 /** scrollLimitEastE6 = 19863300;
 scrollLimitNorthE6 = 51471100;
 scrollLimitWestE6 = 9310900;
 scrollLimitSouthE6 = 44789600; */

// get Views
 mapView = (MapView) findViewById(R.id.MapView);
 gpsState = (ImageView)findViewById(R.id.gpsState);
 imageToggleView = (ImageView)findViewById(R.id.mapToggle);
 locFixIcon = (ImageView)findViewById(R.id.locationfix);

 // set up Animations and Handler for fading the Map Buttons
 uiVisible = true;
 pendingAnimation = false;
 fadeAnimationRunning = false;

 fadeOut = new AlphaAnimation(1,0);
 fadeOut.setDuration(500);
 fadeOut.setAnimationListener(this);

 fadeIn = new AlphaAnimation(0,1);
 fadeIn.setAnimationListener(this);
 fadeIn.setDuration(500);

 fadeUi = new Runnable() {
 @Override
 public void run() {
 fadeAnimationRunning = true;
 for (View element : fadeViews) {
 element.startAnimation(fadeOut);
 }
 }
 };

 fadeTimer = new Handler();
 fadeTimer.postDelayed(fadeUi, 10000);

 fadeViews = new ArrayList<View>();
 fadeViews.add(gpsState);
 fadeViews.add(imageToggleView);
 fadeViews.add(locFixIcon);

 // init some NMEA stuff
 nmeaWriting = true;
 guiUpdater = new Handler();

updateSats = new Runnable() {

 @Override
 public void run() {
 infoBox_sats.setText(String.valueOf(satellites));
 }
 };

 updateGPSIcon = new Runnable() {

 @Override
 public void run() {
 gpsState.setImageResource(R.drawable.gps_nein);

 }
 };

 // set onClick Listeners for Button Views
 imageToggleView.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 if (DEBUG)
 Log.i(DEBUG_TAG, "Toggle clicked!");

 if (loadFirstMapPackFlag)
 loadFirstMapPackFlag = false;
 else
 loadFirstMapPackFlag = true;

 tilesOverlay.onDetach(mapView);
 mapView.getOverlayManager().remove(tilesOverlay);
 tilesOverlay = null;

 // Build new tiles Overlay
 buildTilesLayer();

 if (DEBUG)
 Log.i(DEBUG_TAG, "Added Tiles Overlay!");
 mapView.getOverlayManager().add(0,tilesOverlay);

 mapView.invalidate();
 }
 });

 gpsState.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 showDialog(INFO_DIALOG);

 }
 });

 locFixIcon.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 if (lockPositionFlag){
 lockPositionFlag = false;
 } else {
 lockPositionFlag = true;
 Toast.makeText( getApplicationContext(), "Auf Standort zentrieren ", Toast.LENGTH_SHORT).show();

 Uri mapRequest = Settings.CONTENT_URI;
 Cursor c = getContentResolver().query(mapRequest, null, null, null, null);
 double lat = 0;
 double lon = 0;
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 lat = c.getDouble(c.getColumnIndex(Settings.LAST_LAT));
 lon = c.getDouble(c.getColumnIndex(Settings.LAST_LON));
 }
 }
 if (lat != 0 || lon != 0)
 mapController.setCenter(new GeoPoint(lat, lon));
 }
 }
 });

initializeFields();

 // start the Download Service
 startService(new Intent(this,CartoDownloadService.class));

 // Action Bar Buttons
 ActionBarItem mapsIcon = getActionBar().newActionBarItem(NormalActionBarItem.class).setDrawable(getApplicationContext().getResources().getDrawable(R.drawable.kartenauswahl)).setContentDescription("karten");
 ActionBarItem placesIcon = getActionBar().newActionBarItem(NormalActionBarItem.class).setDrawable(getApplicationContext().getResources().getDrawable(R.drawable.set_waypoint)).setContentDescription("punkte");
 ActionBarItem quitIcon = getActionBar().newActionBarItem(NormalActionBarItem.class).setDrawable(getApplicationContext().getResources().getDrawable(R.drawable.quit_wb)).setContentDescription("beenden");
 getActionBar().addItem(placesIcon);
 getActionBar().addItem(mapsIcon);
 getActionBar().addItem(quitIcon);

getActionBar().setOnActionBarListener(new OnClickActionBarListener());

 // load Settings from Content Provider
 Uri mapRequest = Settings.CONTENT_URI;
 Cursor c = getContentResolver().query(mapRequest, null, null, null, null);
 double lat = 48.21111;
 double lon = 16.378;
 int zoom = 13;
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 lat = c.getDouble(c.getColumnIndex(Settings.LAST_LAT));
 lon = c.getDouble(c.getColumnIndex(Settings.LAST_LON));
 zoom = c.getInt(c.getColumnIndex(Settings.LAST_ZOOM));
 }
 }

 // Create the Map
 // set up the starting Coordinates/Zoomlevel
 lastLocation = new Location("Default");
 lastLocation.setLatitude(lat);
 lastLocation.setLongitude(lon);

 mapController.setZoom(zoom);
 lastLocation.setAccuracy(101);
 mapController.setCenter(new GeoPoint(lat, lon));

 mapView.setMapListener(new MapListener() {

 @Override
 public boolean onZoom(ZoomEvent arg0) {
 // reset out lastKnownLoaction for scroll Limitations
 // lastValidX = 0;
// lastValidY = 0;
 if (lastLocation != null)
 setAccuracyMarker(lastLocation.getAccuracy());

// update zoom level in database
 ContentValues values = new ContentValues();
 values.put(Settings.LAST_ZOOM, mapView.getZoomLevel());
 getContentResolver().update(Settings.CONTENT_URI, values, "", null);

 return false;
 }

 @Override
 public boolean onScroll(ScrollEvent arg0) {

/** Log.i("CartoApp", mapView.getMapCenter().getLatitudeE6() + " / " + mapView.getMapCenter().getLongitudeE6());
 Log.i("CartoApp", "Lat North: " + mapView.getBoundingBox().getLatNorthE6());
 Log.i("CartoApp", "Lon East: " + mapView.getBoundingBox().getLonEastE6());
 Log.i("CartoApp", "Lat South: " + mapView.getBoundingBox().getLatSouthE6());
 Log.i("CartoApp", "Lon West: " + mapView.getBoundingBox().getLonWestE6()); */
 /** if (mapView.getBoundingBox().getLatNorthE6() >= scrollLimitNorthE6 ||
 mapView.getBoundingBox().getLonEastE6() >= scrollLimitEastE6 ||
 mapView.getBoundingBox().getLatSouthE6() <= scrollLimitSouthE6 ||
 mapView.getBoundingBox().getLonWestE6() <= scrollLimitWestE6) {
 if (lastValidX != 0 && lastValidY != 0){

 int newX = arg0.getX();
 int newY = arg0.getY();

 //Log.i("CartoApp","" + newX + " / " + newY);

 if (mapView.getBoundingBox().getLatNorthE6() >= scrollLimitNorthE6 || mapView.getBoundingBox().getLatSouthE6() <= scrollLimitSouthE6)
 newY = lastValidY;
 else if (mapView.getBoundingBox().getLonEastE6() >= scrollLimitEastE6 || mapView.getBoundingBox().getLonWestE6() <= scrollLimitWestE6)
 newX = lastValidX;

 mapView.scrollTo(newX, newY);
 } else {
 int newX = arg0.getX();
 int newY = arg0.getY();
 int latDiff = Math.abs(mapView.getBoundingBox().getLatNorthE6() - mapView.getMapCenter().getLatitudeE6());
 int lonDiff = Math.abs(mapView.getBoundingBox().getLonEastE6() - mapView.getMapCenter().getLongitudeE6());
 GeoPoint gp;
 boolean found = false;

 do {
 gp = TileSystem.PixelXYToLatLong(newX, newY, mapView.getZoomLevel(), null);
 Log.i("CartoApp", gp.getLatitudeE6() + " / " + latDiff + " / " + scrollLimitNorthE6);
 Log.i("CartoApp", gp.getLongitudeE6() + " / " + lonDiff + " / " + scrollLimitEastE6);
 found = true;
 if (gp.getLatitudeE6() + latDiff > scrollLimitNorthE6){
 newY--;
 found = false;
 } else if (gp.getLatitudeE6() - latDiff < scrollLimitSouthE6){
 newY++;
 found = false;
 } else if (gp.getLongitudeE6() + lonDiff > scrollLimitEastE6){
 newX--;
 found = false;
 } else if (gp.getLongitudeE6() - lonDiff < scrollLimitWestE6){
 newX++;
 found = false;
 }
 } while (found == false);
 mapView.scrollTo(newX, newY);
 }

 } else {
 lastValidX = arg0.getX();
 lastValidY = arg0.getY();
 } */

 setMapCenterMarker();
 return false;
 }
 });

 // set up a location Listener
 LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
 mlocListener = new MyLocationListener(mapController);
 mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
 mlocManager.addNmeaListener(this);

// activate standard zoom Butttons
 mapView.setBuiltInZoomControls(true);

 // activate Multitouch
 mapView.setMultiTouchControls(true);

 // init some more stuff
 mapView.setLowPerformanceInterface(this);
 gpsState.setImageResource(R.drawable.gps_nein);

 // Restore when restarting the app
 if (savedInstanceState != null){
 loadFirstMapPackFlag = savedInstanceState.getBoolean(BUNDLE_TOGGLE);
 lockPositionFlag = savedInstanceState.getBoolean(BUNDLE_CENTER);
 }

 }

So this is our onCreate. Here we initialize a lot of stuff we need later in the activity. First we remove the android title with Window.FEATURE_NO_TITLE.

Then we call „setActionBarContentView with our main Layout File. This method comes with GreenDroid and is like setContentView.

Then we set the Type of the ActionBar (normal, empty, dashbord) to empty. This means we have only a title and no home button.

Then we get views and set up a Animation to fade out some Buttons that are over the map. As you can see I use an Array to gather the Views and then loop over these and start the animation

The Handler is used as a timer. I googled about timers and this seems to be a nice solution. Works quite well

The next thing we do is setting up some things for the NMEA, we use NMEA Sentenaces from the GPS Hardware to get the number of satellites that are used to determine the location. First we used only the android Location Service but the problem is that the number of satellites is not a standard value. You can request the value from an Extra Bundle but some vendors do not support it. We test the app on 4 different mobile devices and i can say that Google Nexus S and Sony Ericsson xperia active do not support this Extra Value and the result is null.

Maybe you ask yourself why we initialize a Runable Class that updates some Views from the UI. The answer is simple a problem with threads. The NMEA Sentences are processed in a new thread and when we receive the value of the active satellites we can’t access the UI from this thread. That’s why we call a Handler to update the UI from the main thread.

Now comes the onClickListeners for our views. The image toggle View is a button to display or hide a map pack. If there is more than one map pack active this button just hides or shows the first pack. After setting our loadFirstMapPackFlag we detach out tiles overlay. We need to do this to free the memory we used. If you forget this line the app will crash within 2-3 times you used the button with OutOfMemory Exception.

Then we build the tiles layer again and add it to our mapview.

The gps Button just opens a dialog with further information – we’ll come to the dialogs later in the code.

The last button we have is called locFixIcon. This button scrolls back to the position of the device on the map. And if the map is not moved anymore by the user the map will always center on the position of the device. This means the map will always follow your position. As soon as the user moves the map the fix is broken and needs to be started again with this button.

Since the map Activity is the default main activity on the app we start here a download service. This means the service will be running as long as we don’t quit it. This is important because the service is responsible for downloading data from the internet. At the moment it is only used in one view but since it is a service it will even continue to download while the activity is closed. This means the user can move around in the map without cancelling the download.

We’ll have a closer look at the download service later in the code.

Now we set up the Buttons for our GreenDroid Action bar. In our app we have 3 Items. The first is used to load the activity to save a marker on the map. The second item opens the activity where you can download and deselect map packs. The last button is used to quit the app.

After setting up the buttons we still need to set the Listener class for the ActionBar. We could have used a new class but i prefer to use the activity as listener. So we jsut implemented the listener interface at the class declaration and then override the necessary methods.

Now we read some informations from the database. We need to get the last position and the last zoomlevel the user had. It is more comfortable for the user if the app always starts where the user left it. Later in the code you’ll see where and how we save this information.

After we get the query result from the Content Resolver (We declared the content Provider in the manifest file) we just have to get the result. By default there should ALWAYS be a value because we initialize the database with some values. The only case where we do not get a result could be if the database is corrupt or some other heavy failure. After we have our last known latitude, longitude and zoomlevel we create our own Location Object and set it to our new position values. Then we set the Center of the map to our last position and the zoom to our last known zoomlevel.

The Map Listener from Mapview has 2 methods to override. onZoom and onScroll. OnScroll is not really used in our app. It just sets the center marker. The code that is there as comments is a try to limit the map to some defined bounds. It’s not really working always but it’s a nice start if someone wants to complete it.

More litte more  interesting is the onZoom Method because we write the active zoom level to our settings database. As you see in the code it’s very simple to use a content provider to write stuff to the database.

After the mapListener we create a location listener and request updates if the gps status changes. Also here we register for nmea updates.

Then we set up the zoom buttons and the multi touch for our mapView object.

The method „setLowPerformanceInterface“ will show an error if you copy the code because this method not standard osmdroid. We changed the code to give a callback when the mapView build times are to high. This gives us the chance to reduce map packs (that are not in this area) or warn the user to activate less map packs. If someone is interested in this interface just tell me and i’ll post the code from our osmdroid project.

At last we check the bundle for out button states. We need to to this because if the user turns the device the app gets restarted and since we want to keep our button state we need to load this here.

Now we have some methods for our dialogs:


@Override
 protected void onPrepareDialog(int id, Dialog dialog) {
 switch (id) {
 case INFO_DIALOG:
 prepareInfoDialog(dialog);
 return;
 case MARKER_DIALOG:
 prepareMarkerDialog(dialog);
 return;
 default:
 return;
 }
 }

@Override
 protected Dialog onCreateDialog(int id) {
 switch (id) {
 case INFO_DIALOG:
 Dialog infoDialog = new Dialog(this);
 infoDialog.setContentView(R.layout.main_info_dialog);
 infoDialog.setTitle("Info");
 return infoDialog;

 case QUIT_DIALOG:
 AlertDialog.Builder builder = new Builder(this);
 builder.setMessage(R.string.quitDialogText).setCancelable(false).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 finish();
 }
 }).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 /* we do not do anything here */
 }
 });
 return builder.create();

 case MARKER_DIALOG:
 Dialog markerDialog = new Dialog(this);
 markerDialog.setContentView(R.layout.marker_info_dialog);
 markerDialog.setTitle("Marker Info");
 return markerDialog;

 default:
 return null;
 }
 }

In this activity we have 3 Dialogs:

  1. The „Info“ Dialog shows Information about the current position, speed, altitude and accuracy of the GPS and  can be startet on the menu or by clicking on the „GPS“ Icon on top of the map
  2. The „Marker Info“ Dialog shows Information about the marker and can be opened by clicking on a marker on the map
  3. The „Quit“ Dialog is just a simple verification if the user really wants to close the app.

The first method „onPrepareDialog“ is called after the Dialog is created but before it is displayed. „onCreateDialog“ is the method where the dialog is created. As you can see the Quit Dialog is created with the AlertDialog Builder. Like this we just have to set up the buttons and the text and the rest is done from the Class itself. The Info dialog needs some more stuff like layouts and more text than the quit dialog.

The next methods we have are used to build the menu:


@Override
 public boolean onOptionsItemSelected(MenuItem item) {
 if (DEBUG)
 Log.i(DEBUG_TAG, "Item selected: " + item.getItemId());
 switch (item.getItemId()) {
 case R.id.info:
 showDialog(INFO_DIALOG);
 return true;
 case R.id.preferences:
 return true;
 case R.id.quit:
 showDialog(QUIT_DIALOG);
 return true;
 default:
 return super.onOptionsItemSelected(item);
 }

 }

@Override
 public boolean onCreateOptionsMenu(Menu menu) {
 MenuInflater inflater = getMenuInflater();
 inflater.inflate(R.menu.map_manu, menu);
 return true;
 }

As you can see we only need 2 methods: onCreateMenu and onOptionsItemSelected. First we create the menu with the MenuInflater Class and a Layoutfile in the menu folder of our resources. When the user clicks an item android calls our onOptionsItemSelected and we check what item that was by comparing the item id.

The next code is responsible to save some stuff when the app is closed. This can happen when the user flips the phone to landscape/portrait mode or when other activitys are infront of this one and it gets destroyed because more memory is needed by the android system.


@Override
 protected void onSaveInstanceState(Bundle outState) {
 outState.putInt(BUNDLE_SCROLLX, mapView.getScrollX());
 outState.putInt(BUNDLE_SCROLLY, mapView.getScrollY());
 outState.putInt(BUNDLE_ZOOM, mapView.getZoomLevel());
 outState.putBoolean(BUNDLE_TOGGLE, loadFirstMapPackFlag);
 outState.putBoolean(BUNDLE_CENTER, lockPositionFlag);
 super.onSaveInstanceState(outState);
 }

@Override
 protected void onRestoreInstanceState(Bundle savedInstanceState) {
 if (mapView != null && savedInstanceState != null){
 if (savedInstanceState.getInt(BUNDLE_ZOOM) != 0)
 mapView.getController().setZoom(savedInstanceState.getInt(BUNDLE_ZOOM));
 if (savedInstanceState.getInt(BUNDLE_SCROLLX) != 0 && savedInstanceState.getInt(BUNDLE_SCROLLY) != 0)
 mapView.scrollTo(savedInstanceState.getInt(BUNDLE_SCROLLX), savedInstanceState.getInt(BUNDLE_SCROLLY));
 }
 super.onRestoreInstanceState(savedInstanceState);
 }

As you can see we save the current position on the map and our zoom level. Since we have 2 buttons on top of the map we also save their state (active or inactive).

I guess some will ask themself why I do no load these 2 boolean variables in onRestoreInstanceState. The answer is simple: One button changes the map packs that get loaded. The User can tell the system not to load the first map pack. This feature makes it a bit easier to switch between the map pack you downloaded and the open street map you have in the background. The tiles layer with the map packs get build and loaded in our „onStart“ method. We’ll talk later about this in detail. Since onRestoreInstanceState is called AFTER onStart we would be too late to set the variable. That’s why we get the value that we saved in onCreate (at the end of onCreate). The parameter Bundle from onCreate is the same as we have here in onRestoreInstanceState. So it’s just a metter of timing when you load the stuff you saved before.

Next we have a look at „onDestroy“, „onPause“, „onResume“, „onStart“ and „onStop“.


@Override
 protected void onDestroy() {
 stopService(new Intent(getApplicationContext(), CartoDownloadService.class));
 LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
 mlocManager.removeUpdates(mlocListener);
 mlocManager.removeNmeaListener(this);
 mapView = null;

 super.onDestroy();
 }

@Override
 protected void onPause() {
 try {
 if (sr != null)
 sr.stop();
 } catch (Exception e) {
 }

 pos = null;
 pis = null;
 sr = null;

 nmeaWriting = false;
 super.onPause();
 }

@Override
 protected void onResume() {

pis = new PipedInputStream();
 try {
 pos = new PipedOutputStream(pis);
 } catch (IOException e) {
 e.printStackTrace();
 }
 sr = new SentenceReader(pis);
 sr.addSentenceListener(this);
 sr.start();
 nmeaWriting = true;
 super.onResume();
 }

@Override
 protected void onStart() {
 MapTileProviderBase tilesource = new MapTileProviderBasic(getApplicationContext(), TileSourceFactory.MAPNIK);
 tilesource.setTileRequestCompleteHandler(new SimpleInvalidationHandler(mapView));
 mapView.getOverlayManager().setTilesOverlay(new TilesOverlay(tilesource, new DefaultResourceProxyImpl(getApplicationContext())));

 buildTilesLayer();
 if (DEBUG)
 Log.i(DEBUG_TAG, "Added Tiles Overlay!");
 mapView.getOverlayManager().add(tilesOverlay);

buildWaypointLayer();
 mapView.getOverlayManager().add(waypointOverlay);

positionOverlay = new aItemizedOverlay(getApplicationContext(), new ArrayList<OverlayItem>(), null);
 mapView.getOverlayManager().add(positionOverlay);
 setPositionMarker();
 if (lastLocation != null)
 setAccuracyMarker(lastLocation.getAccuracy());

 markerOverlay = new aItemizedOverlay(getApplicationContext(), new ArrayList<OverlayItem>(), null);
 mapView.getOverlayManager().add(markerOverlay);
 setMapCenterMarker();

 ScaleBarOverlay mScaleBarOverlay = new ScaleBarOverlay(this);
 mScaleBarOverlay.setScaleBarOffset(mScaleBarOverlay.xdpi / 2, 20);
 mScaleBarOverlay.enableScaleBar();

 mapView.getOverlayManager().add(mScaleBarOverlay);

 mapView.invalidate();
 super.onStart();
 }

@Override
 protected void onStop() {

 if (DEBUG)
 Log.i(DEBUG_TAG, "onStop executed!");

 mapView.getOverlayManager().onDetach(mapView);

 while (mapView.getOverlayManager().size() > 0) {
 mapView.getOverlayManager().remove(0);
 }

super.onStop();
 }

OnDestory:

This is the last method that is called before the app is closed. It is the opposite of onCreate. Here we free our MapView Object and remove some callbacks like the Nmea and Location Listener. We also shut down our Download Service that was started on onCreate.

OnPause:

This method is called if the activity is paused and not in foreground anymore. The only thing we do here concerns the Nmea Reading. Since the parsing is using a lot of cpu power we want to stop the nmea parsing while the activity is not infront.

Maybe you ask yourself why i null the PipedInput and Output stream and the SentenceReader . The answer is simple: I found out that often the connection between the input and output stream gets lost when the app isn’t in front. When the app resumes and the code wants to use this piped connecttion an exception occurs that says „pipe is broken“. That’s why we shut down the whole communication and created it again when the activity resumes.

OnResume:

Here we build up the PipedInput, Output Stream and the SentenceReader from MarineApi again.

OnStart:

Ok this method is very important. Here we build up all the layers we want to display:

Mapnik Base Layer (don’t forgett to ser the CompleteHandler – or the map will not refresh with new downloaded tiles)

Tiles Layer (more information later)

Waypoint Layer (more information later)

position Overlay (the position overlay is an item overlay that is responsible to show the markers for the current position and accuracy of the GPS Signal. Since we want these markers to display on top of the waypoints we create our own layer for this.)

MarkerOverlay (This is simple the cross in the middle of the Screen – we have this since new waypoints are set to this center position and like this the user can be more precise placing his waypoints.

At last we activate the Scale Bar from osmdroid.

onStop:

As you can see we remove all overlays again. Very important is to run onDetach before we do this. Only like this all Objects are released and the garbage colletor can get the memory back.

Animation Methods:


@Override
 public void onAnimationEnd(Animation animation) {
 if (uiVisible){
 uiVisible = false;
 for (View element : fadeViews) {
 element.setVisibility(View.INVISIBLE);
 }

 } else {
 fadeTimer.removeCallbacks(fadeUi);
 fadeTimer.postDelayed(fadeUi, 10000);
 uiVisible = true;
 }

 if (pendingAnimation) {
 pendingAnimation = false;
 for (View element : fadeViews) {
 element.startAnimation(fadeIn);
 }
 } else
 fadeAnimationRunning = false;
 }

@Override
 public void onAnimationRepeat(Animation animation) {

 }

@Override
 public void onAnimationStart(Animation animation) {
 for (View element : fadeViews) {
 element.setVisibility(View.VISIBLE);
 }
 }

Since we have some Buttons that are on top of our map we want to hide them after some time. To do this we use the Animation Class (in our case the AlphaAnimation) from Android. From the Animation Interface we get these methods above.
These methods get called when an animation starts or ends. So what do i do here: First i check if our Buttons are visible or not. If the UI is visible and the animation ends that means we just had a complete fade out. If we do not do anything the button would just get visible again because the alpha value returns to 100 after the animation ends. To avoid the button showing again we set it’s visibility state to invisible.
(difference in Android 4.0: even if the button is in invisible state the user can still press is)
If the UI is invisible and the animation ends we just faded it in. Here we just need to set up the timer for fade out again.
PendingAnimation only occurs if a fade out is running and the user touches the display. This variable gets set in the onTouchEvent method. We’ll talk about this later.

Ok here our last override methods onTouchEvent and onLowPerformance:

</pre>
@Override
 public boolean onTouchEvent(MotionEvent event) {

 if (DEBUG)
 Log.i(DEBUG_TAG, "Touch Event on Map, Visible: " + uiVisible + " / Fading: " + fadeAnimationRunning);
 if (!uiVisible) {
 if (!fadeAnimationRunning){
 fadeAnimationRunning = true;
 for (View element : fadeViews) {
 element.startAnimation(fadeIn);
 }
 if (DEBUG)
 Log.i(DEBUG_TAG, "Fade Event Started");
 }
 } else {
 if (fadeAnimationRunning)
 pendingAnimation = true;
 fadeTimer.removeCallbacks(fadeUi);
 fadeTimer.postDelayed(fadeUi, 3000);
 }

 return super.onTouchEvent(event);
 }

 @Override
 public void onLowPerformance() {
 if (DEBUG)
 Log.i(DEBUG_TAG, "Low Performance reported from MapView");
 }
<pre>

OnTouchEvent is a method from Android Activity. We need this because osmdroid forwards the Touch Events and like this we can fade our UI Buttons.
OnLowPerformance is a method from an interface i wrote myself. I wanted to get a notice in my map class if the ms to draw the map is above 500. This method gets called from osmdroid mapView Class. Guess most people will not need it.

So now we come to some additional methods we use:

</pre>
private void prepareMarkerDialog(final Dialog dialog){

 TextView name = (TextView) dialog.findViewById(R.id.value_name);
 TextView desc = (TextView) dialog.findViewById(R.id.value_desc);
 TextView lat = (TextView) dialog.findViewById(R.id.value_lat);
 TextView lon = (TextView) dialog.findViewById(R.id.value_lon);
 TextView date = (TextView) dialog.findViewById(R.id.value_date);
 TextView time = (TextView) dialog.findViewById(R.id.value_time);
 Button close = (Button)dialog.findViewById(R.id.close);

 if (lastTappedMarker != null){
Cursor c = getContentResolver().query(Uri.withAppendedPath(Markers.CONTENT_URI, "/" + lastTappedMarker.getDesc()), null, null, null, null);
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 desc.setText(c.getString(c.getColumnIndex(Markers.NOTIZ)));
 date.setText(c.getString(c.getColumnIndex(Markers.DATUM)));
 time.setText(c.getString(c.getColumnIndex(Markers.ZEIT)));
 }
 }
 c.close();
 name.setText(lastTappedMarker.getName());
 lat.setText(formatNumber(Math.round(lastTappedMarker.getLatE6()*1E-3)*1E-3, "0.0##"));
 lon.setText(formatNumber(Math.round(lastTappedMarker.getLonE6()*1E-3)*1E-3, "0.0##"));

 }

 close.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 dialog.dismiss();

 }
 });
 }

 private void prepareInfoDialog(final Dialog dialog){
 if (DEBUG)
 Log.i(DEBUG_TAG, "Dialog prepared");
infoBox_provider_accuracy = (TextView)dialog.findViewById(R.id.provider_accuracy_value);
 infoBox_gps_accuracy = (TextView)dialog.findViewById(R.id.gps_accuracy_value);
 infoBox_lat = (TextView)dialog.findViewById(R.id.latitude_value);
 infoBox_lon = (TextView)dialog.findViewById(R.id.longitude_value);
 infoBox_altitude = (TextView)dialog.findViewById(R.id.altitude_value);
 infoBox_speed = (TextView)dialog.findViewById(R.id.speed_value);
 TextView zoomLevel = (TextView)dialog.findViewById(R.id.zoomlevel_value);
 Button infoBox_close = (Button)dialog.findViewById(R.id.close);

 zoomLevel.setText(String.valueOf(mapView.getZoomLevel()));
 infoBox_lon.setText(formatNumber(Math.round(mapView.getMapCenter().getLongitudeE6()*1E-3)*1E-3,"0.0##"));
 infoBox_lat.setText(formatNumber(Math.round(mapView.getMapCenter().getLatitudeE6()*1E-3)*1E-3, "0.0##"));
 infoBox_provider_accuracy.setText(R.string.notavailable);
 infoBox_gps_accuracy.setText(R.string.notavailable);
 infoBox_altitude.setText(R.string.notavailable);
 infoBox_speed.setText(R.string.notavailable);

 if (lastLocation != null) {
 if (lastLocation.getProvider().equals(LocationManager.GPS_PROVIDER))
 infoBox_gps_accuracy.setText(String.valueOf(lastLocation.getAccuracy()));
 else if (lastLocation.getProvider().equals(LocationManager.NETWORK_PROVIDER))
 infoBox_provider_accuracy.setText(String.valueOf(lastLocation.getAccuracy()));

 infoBox_altitude.setText(String.valueOf(Math.round(lastLocation.getAltitude())));
 infoBox_speed.setText(String.valueOf(lastLocation.getSpeed()*3.6));
 }

 infoBox_close.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 dialog.dismiss();
 }
 });
 }
<pre>

explanation coming soon …

</pre>
private void buildWaypointLayer(){
 Cursor c;

OnItemGestureListener<OverlayItem> pOnItemGestureListener = new myItemGestureListener<OverlayItem>();
 waypointOverlay = new aItemizedOverlay(getApplicationContext(), new ArrayList<OverlayItem>(), pOnItemGestureListener);

 Resources res = getResources();

 c = getContentResolver().query(Markers.CONTENT_URI, null, null, null, null);
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 do{
 String name = c.getString(c.getColumnIndex(Markers.NAME));
 int latE6 = c.getInt(c.getColumnIndex(Markers.LATITUDE));
 int lonE6 = c.getInt(c.getColumnIndex(Markers.LONGITUDE));
 if (c.getInt(c.getColumnIndex(Maps.AKTIV)) == 1){
 Drawable marker = res.getDrawable(R.drawable.waypoint);
 OverlayItem markerItem = new OverlayItem(name,c.getString(c.getColumnIndex(Markers._ID)),new GeoPoint(latE6, lonE6));

 markerItem.setMarker(marker);
 markerItem.setMarkerHotspot(HotspotPlace.LOWER_LEFT_CORNER);

 waypointOverlay.addItem(markerItem);
 }
 } while (c.moveToNext());
 }
 }
 c.close();
 }
<pre>

explanation coming soon …

</pre>
private void setPositionMarker(){
 if (lastLocation != null && mapView != null){
 if (DEBUG)
 Log.i(DEBUG_TAG, "setting Position marker to last location...");

 if (positionMarker != null)
 positionOverlay.removeItem(positionMarker);

Resources res = getResources();
 positionMarkerDrawable = (Drawable) res.getDrawable(R.drawable.gps_position_animated);

 positionMarker = null;
 positionMarker = new OverlayItem("Position Marker","Description of my Marker",new GeoPoint(lastLocation.getLatitude(), lastLocation.getLongitude()));
 positionMarker.setMarker(positionMarkerDrawable);
 positionMarker.setMarkerHotspot(HotspotPlace.CENTER);
 positionOverlay.addItem(positionMarker);
 mapView.invalidate();

 if (DEBUG)
 Log.i(DEBUG_TAG, "setting Position marker... finished");

 }

}

 private void setMapCenterMarker(){
 if (mapView != null){
 markerOverlay.removeAllItems();
 Resources res = getResources();
 Drawable posMarker = res.getDrawable(R.drawable.display_mitte);

 OverlayItem mapCenterMarker = new OverlayItem("Map Center Marker","Description of my Marker",new GeoPoint(mapView.getMapCenter().getLatitudeE6()*1E-6, mapView.getMapCenter().getLongitudeE6()*1E-6));
 mapCenterMarker.setMarker(posMarker);
 mapCenterMarker.setMarkerHotspot(HotspotPlace.CENTER);
 markerOverlay.addItem(mapCenterMarker);

 mapView.invalidate();
 }
 }

 private void setAccuracyMarker(float accuracy){
 if (lastLocation != null && mapView != null){
 if (DEBUG)
 Log.i(DEBUG_TAG, "setting Accuracy marker...");
 if (accuracyMarker != null)
 positionOverlay.removeItem(accuracyMarker);

Resources res = getResources();

 if ((mapView.getZoomLevel() == 11 && accuracy > 500 && accuracy <= 1000) ||
 (mapView.getZoomLevel() == 12 && accuracy > 250 && accuracy <= 1000) ||
 (mapView.getZoomLevel() == 13 && accuracy > 100 && accuracy <= 1000) ||
 (mapView.getZoomLevel() == 14 && accuracy > 50 && accuracy <= 1000) ||
 (mapView.getZoomLevel() == 15 && accuracy > 25 && accuracy <= 1000))
 {
 Drawable marker = res.getDrawable(R.drawable.gps_genauigkeit_26);
 if (mapView.getZoomLevel() == 15 && accuracy > 500)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_420);
 else if (mapView.getZoomLevel() == 15 && accuracy > 250)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_210);
 else if (mapView.getZoomLevel() == 15 && accuracy > 100)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_105);
 else if (mapView.getZoomLevel() == 15 && accuracy > 75)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_42);
 else if (mapView.getZoomLevel() == 15 && accuracy > 50)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_31);
 else if (mapView.getZoomLevel() == 15 && accuracy > 0)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_21);
 if (mapView.getZoomLevel() == 14 && accuracy > 500)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_210);
 else if (mapView.getZoomLevel() == 14 && accuracy > 250)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_105);
 else if (mapView.getZoomLevel() == 14 && accuracy > 100)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_52);
 else if (mapView.getZoomLevel() == 14 && accuracy > 75)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_21);
 else if (mapView.getZoomLevel() == 14 && accuracy > 50)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_16);
 if (mapView.getZoomLevel() == 13 && accuracy > 500)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_105);
 else if (mapView.getZoomLevel() == 13 && accuracy > 250)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_52);
 if (mapView.getZoomLevel() == 12 && accuracy > 500)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_52);

 accuracyMarker = new OverlayItem("Accuracy Marker","Description of my Marker",new GeoPoint(lastLocation.getLatitude(), lastLocation.getLongitude()));
 accuracyMarker.setMarker(marker);
 accuracyMarker.setMarkerHotspot(HotspotPlace.CENTER);
 positionOverlay.addItem(accuracyMarker);
 }

 if (accuracy <= 25)
 gpsState.setImageResource(R.drawable.gps_ja);
 else if (accuracy <= 100)
 gpsState.setImageResource(R.drawable.gps_schlecht);
 else
 gpsState.setImageResource(R.drawable.gps_nein);

 mapView.invalidate();

 if (DEBUG)
 Log.i(DEBUG_TAG, "setting Accuracy marker... finished");
 }
 }
<pre>

explanation coming soon …

</pre>
private void initializeFields(){
 loadFirstMapPackFlag = true;
 lockPositionFlag = false;

 mapController = mapView.getController();
 }

 private void buildTilesLayer(){
 List<String> overlayArchiveResources = new ArrayList<String>(1);

 Uri mapRequest = at.ac.univie.carto.contentprovider.CartoContentProvider.Maps.CONTENT_URI;
 Cursor c = getContentResolver().query(mapRequest, null, null, null, null);
 boolean mapLeftOut = false;
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 do{
 int anzahl = c.getInt(c.getColumnIndex(Maps.DATEIANZAHL));
 String dateiPfad = c.getString(c.getColumnIndex(Maps.DATEIPFAD));
 String dateiName = c.getString(c.getColumnIndex(Maps.DATEINAME));
 if (c.getInt(c.getColumnIndex(Maps.AKTIV)) == 1){
 if (!mapLeftOut && !loadFirstMapPackFlag){
 mapLeftOut = true;
 } else {
 for (int i = 0; i < anzahl; i++) {
 Log.i("map Controller", "Added Map " + dateiPfad + dateiName + i + ".zip");
 overlayArchiveResources.add(dateiPfad + dateiName + i + ".zip");
 }
 }
 }

 } while (c.moveToNext());
 }
 }
 c.close();
 List<MapTileModuleProviderBase> overlayFileProvider = new ArrayList<MapTileModuleProviderBase>(2);
 File overlayFile;
 myTileSource overlayFileTileSource = null;
 IArchiveFile[] overlayFileArchive = new IArchiveFile[1];
 for (String path : overlayArchiveResources) {
 overlayFile = new File(path);
 if (overlayFile.exists())
 overlayFileArchive[0] = ArchiveFileFactory.getArchiveFile(overlayFile);
 else
 continue;
 overlayFile = null;
 overlayFileTileSource = new myTileSource("map", null, 8, 16, 256, ".jpg");
 overlayFileProvider.add(new MapTileFileArchiveProvider(new SimpleRegisterReceiver(getApplicationContext()), overlayFileTileSource, overlayFileArchive));
 }
 overlayFileArchive = null;
 MapTileModuleProviderBase[] overlayFileProvider2 = new MapTileModuleProviderBase[overlayFileProvider.size()];
 MapTileProviderArray overlayFileProviderArray1 = new MapTileProviderArrayExtended(overlayFileTileSource,null, overlayFileProvider.toArray(overlayFileProvider2));
 overlayFileProviderArray1.setTileRequestCompleteHandler(mapView.getTileRequestCompleteHandler());
 tilesOverlay = new TilesOverlay(overlayFileProviderArray1, getApplicationContext());
 tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
 overlayFileProvider = null;
 overlayFileProvider2 = null;
 overlayFileProviderArray1 = null;

}

 private String formatNumber(double Value, String formatString){
 DecimalFormat formatter = new DecimalFormat(formatString);
 return formatter.format(Value);
 }
<pre>

explanation coming soon …

Now we come to some classes we use:

</pre>
private class OnClickActionBarListener implements OnActionBarListener {

@Override
 public void onActionBarItemClicked(int position) {
 if (position == 2){
 showDialog(QUIT_DIALOG);
 } else if (position == 1){
 Intent mapSelect = new Intent().setComponent(new ComponentName(getApplicationContext(), MapSelect.class));
 startActivity(mapSelect);
 } else if (position == 3){
 Intent waypointSelect = new Intent().setComponent(new ComponentName(getApplicationContext(), WaypointSelect.class));
 startActivity(waypointSelect);
 } else if (position == 0){
 Intent waypointAdd = new Intent().setComponent(new ComponentName(getApplicationContext(), WaypointAdd.class));
 int[] location = new int[2];
 location[0] = mapView.getMapCenter().getLatitudeE6();
 location[1] = mapView.getMapCenter().getLongitudeE6();
 waypointAdd.putExtra(R.string.app_prefix + ".location", location);
 startActivity(waypointAdd);
 }
 }

 }
<pre>

explanation coming soon …

</pre>
public class myTileSource extends BitmapTileSourceBase {

public myTileSource(String aName, string aResourceId, int aZoomMinLevel,
 int aZoomMaxLevel, int aTileSizePixels, String aImageFilenameEnding) {
 super(aName, aResourceId, aZoomMinLevel, aZoomMaxLevel, aTileSizePixels,
 aImageFilenameEnding);
 }

}
<pre>

explanation coming soon …

</pre>
public class myItemGestureListener<T extends OverlayItem> implements OnItemGestureListener<T> {

@Override
 public boolean onItemSingleTapUp(int index, T item) {
 if (DEBUG)
 Log.i(DEBUG_TAG, "Item clicked: " + item.getTitle());
 lastTappedMarker = new Marker();
 lastTappedMarker.setName(item.mTitle);
 lastTappedMarker.setDesc(item.mDescription);
 lastTappedMarker.setLatE6(item.mGeoPoint.getLatitudeE6());
 lastTappedMarker.setLonE6(item.mGeoPoint.getLongitudeE6());
 showDialog(MARKER_DIALOG);
 return false;
 }

@Override
 public boolean onItemLongPress(int index, T item) {
 return false;
 }

&nbsp;

}
<pre>

explanation coming soon …

</pre>
public class MyLocationListener implements LocationListener
 {
 private MapController mapController;
 private long lastGPSSignal;
 private long lastNetworkSignal;

 public MyLocationListener(MapController controller){
 this.lastGPSSignal = 0;
 this.lastNetworkSignal = 0;
 this.mapController = controller;
 }
 @Override
 public void onLocationChanged(Location loc)
 {
 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER))
 lastGPSSignal = System.currentTimeMillis();
 if (loc.getProvider().equals(LocationManager.NETWORK_PROVIDER))
 lastNetworkSignal = System.currentTimeMillis();

 if (DEBUG)
 Log.i(DEBUG_TAG, "new Location from Provider " + lastLocation.getProvider() + " received with acc " + lastLocation.getAccuracy() + " for InfoBoxField: " + infoBox_provider_accuracy);
 lastLocation = loc;
 if (lockPositionFlag)
 this.mapController.setCenter(new GeoPoint(loc.getLatitude(), loc.getLongitude()));

 if (infoBox_gps_accuracy != null && lastLocation.getProvider().equals(LocationManager.GPS_PROVIDER) && lastLocation != null)
 infoBox_gps_accuracy.setText(String.valueOf(lastLocation.getAccuracy()));
 if (infoBox_provider_accuracy != null && lastLocation.getProvider().equals(LocationManager.NETWORK_PROVIDER) && lastLocation != null)
 infoBox_provider_accuracy.setText(String.valueOf(lastLocation.getAccuracy()));
 if (lastLocation.getProvider().equals(LocationManager.NETWORK_PROVIDER)){
 if (lastGPSSignal == 0 || (System.currentTimeMillis() - lastGPSSignal) > GPSTTIMEOUT) {
 if (infoBox_lat != null && mapView != null)
 infoBox_lat.setText(formatNumber(Math.round(mapView.getMapCenter().getLatitudeE6()*1E-3)*1E-3, "0.0##"));
 if (infoBox_lon != null && mapView != null)
 infoBox_lon.setText(formatNumber(Math.round(mapView.getMapCenter().getLongitudeE6()*1E-3)*1E-3, "0.0##"));
 }
 } else if (lastLocation.getProvider().equals(LocationManager.GPS_PROVIDER)){
 if (infoBox_lat != null && mapView != null)
 infoBox_lat.setText(formatNumber(Math.round(mapView.getMapCenter().getLatitudeE6()*1E-3)*1E-3, "0.0##"));
 if (infoBox_lon != null && mapView != null)
 infoBox_lon.setText(formatNumber(Math.round(mapView.getMapCenter().getLongitudeE6()*1E-3)*1E-3, "0.0##"));
 }
 if (infoBox_speed != null && mapView != null)
 infoBox_speed.setText(formatNumber(lastLocation.getSpeed()*3.6, "0.0##"));
 if (infoBox_altitude != null && mapView != null)
 infoBox_altitude.setText(String.valueOf(Math.round(lastLocation.getAltitude())));

 ContentValues values = new ContentValues();
 values.put(Settings.LAST_LAT, loc.getLatitude());
 values.put(Settings.LAST_LON, loc.getLongitude());
 getContentResolver().update(Settings.CONTENT_URI, values, "", null);

setAccuracyMarker(loc.getAccuracy());
 setPositionMarker();

 }
 @Override
 public void onProviderDisabled(String provider)
 {
 gpsState.setImageResource(R.drawable.gps_nein);
 }

@Override
 public void onProviderEnabled(String provider)
 {

}

@Override
 public void onStatusChanged(String provider, int status, Bundle extras)
 {

}

}
<pre>

explanation coming soon …

</pre>
private class aItemizedOverlay extends ItemizedIconOverlay<OverlayItem>{

public aItemizedOverlay(
 Context pContext,
 List<OverlayItem> pList,
 org.osmdroid.views.overlay.ItemizedIconOverlay.OnItemGestureListener<OverlayItem> pOnItemGestureListener) {
 super(pContext, pList, pOnItemGestureListener);
 }

@Override
 public boolean onTouchEvent(MotionEvent event, MapView mapView) {
 lockPositionFlag = false;
 return false;
 }

 }
<pre>

explanation coming soon …

Ok and here now the complete code:

</pre>
package at.ac.univie.carto.activitys;

import java.io.File;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import microsoft.mappoint.TileSystem;
import net.sf.marineapi.nmea.event.SentenceEvent;
import net.sf.marineapi.nmea.event.SentenceListener;
import net.sf.marineapi.nmea.io.SentenceReader;
import net.sf.marineapi.nmea.sentence.GSVSentence;
import net.sf.marineapi.nmea.sentence.SentenceId;
import net.sf.marineapi.nmea.util.SatelliteInfo;

import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.ResourceProxy.string;
import org.osmdroid.events.MapListener;
import org.osmdroid.events.ScrollEvent;
import org.osmdroid.events.ZoomEvent;
import org.osmdroid.events.LowPerformanceInterface;
import org.osmdroid.tileprovider.MapTileProviderArray;
import org.osmdroid.tileprovider.MapTileProviderArrayExtended;
import org.osmdroid.tileprovider.MapTileProviderBase;
import org.osmdroid.tileprovider.MapTileProviderBasic;
import org.osmdroid.tileprovider.modules.ArchiveFileFactory;
import org.osmdroid.tileprovider.modules.IArchiveFile;
import org.osmdroid.tileprovider.modules.MapTileFileArchiveProvider;
import org.osmdroid.tileprovider.modules.MapTileModuleProviderBase;
import org.osmdroid.tileprovider.tilesource.BitmapTileSourceBase;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.tileprovider.util.SimpleInvalidationHandler;
import org.osmdroid.tileprovider.util.SimpleRegisterReceiver;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.ItemizedIconOverlay;
import org.osmdroid.views.overlay.OverlayItem;
import org.osmdroid.views.overlay.ScaleBarOverlay;
import org.osmdroid.views.overlay.TilesOverlay;
import org.osmdroid.views.overlay.ItemizedIconOverlay.OnItemGestureListener;
import org.osmdroid.views.overlay.OverlayItem.HotspotPlace;

import greendroid.app.GDActivity;
import greendroid.widget.ActionBar;
import greendroid.widget.ActionBarItem;
import greendroid.widget.NormalActionBarItem;
import greendroid.widget.ActionBar.OnActionBarListener;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.AlertDialog.Builder;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.location.GpsStatus.NmeaListener;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import at.ac.univie.carto.R;
import at.ac.univie.carto.constants.CartoConstants;
import at.ac.univie.carto.contentprovider.CartoContentProvider.Maps;
import at.ac.univie.carto.contentprovider.CartoContentProvider.Markers;
import at.ac.univie.carto.contentprovider.CartoContentProvider.Settings;
import at.ac.univie.carto.data.wrapper.Marker;
import at.ac.univie.carto.services.CartoDownloadService;

public class Map extends GDActivity implements CartoConstants, AnimationListener, LowPerformanceInterface {

private static final String BUNDLE_SCROLLX = "scrollx";
 private static final String BUNDLE_SCROLLY = "scrolly";
 private static final String BUNDLE_ZOOM = "zoom";
 private static final String BUNDLE_TOGGLE = "toggle";
 private static final String BUNDLE_CENTER = "center";

 private static final int INFO_DIALOG = 1;
 private static final int QUIT_DIALOG = 2;
 private static final int MARKER_DIALOG = 3;

 private MapView mapView;
 private MapController mapController;

 private TilesOverlay tilesOverlay;
 private ItemizedIconOverlay<OverlayItem> markerOverlay;
 private ItemizedIconOverlay<OverlayItem> positionOverlay;
 private ItemizedIconOverlay<OverlayItem> waypointOverlay;

private OverlayItem positionMarker;
 private Drawable positionMarkerDrawable;
 private OverlayItem accuracyMarker;

 private TextView infoBox_lat;
 private TextView infoBox_lon;
 private TextView infoBox_gps_accuracy;
 private TextView infoBox_provider_accuracy;
 private TextView infoBox_speed;
 private TextView infoBox_altitude;

 private LocationListener mlocListener;
 private Location lastLocation;

 private ImageView gpsState;
 private ImageView imageToggleView;
 private ImageView locFixIcon;

 private Handler fadeTimer;
 private Animation fadeOut;
 private Animation fadeIn;
 private boolean fadeAnimationRunning;
 private boolean pendingAnimation;
 private boolean uiVisible;
 private Runnable fadeUi;
 private List<View> fadeViews;

 private boolean loadFirstMapPackFlag;
 private boolean lockPositionFlag;
 private Marker lastTappedMarker;
@Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 requestWindowFeature(Window.FEATURE_NO_TITLE);
 setActionBarContentView(R.layout.main);
 getActionBar().setType(ActionBar.Type.Empty);

mapView = (MapView) findViewById(R.id.MapView);
 gpsState = (ImageView)findViewById(R.id.gpsState);
 imageToggleView = (ImageView)findViewById(R.id.mapToggle);
 locFixIcon = (ImageView)findViewById(R.id.locationfix);

 uiVisible = true;
 pendingAnimation = false;
 fadeAnimationRunning = false;

 fadeOut = new AlphaAnimation(1,0);
 fadeOut.setDuration(500);
 fadeOut.setAnimationListener(this);

 fadeIn = new AlphaAnimation(0,1);
 fadeIn.setAnimationListener(this);
 fadeIn.setDuration(500);

 fadeUi = new Runnable() {
 @Override
 public void run() {
 fadeAnimationRunning = true;
 for (View element : fadeViews) {
 element.startAnimation(fadeOut);
 }
 }
 };

 fadeTimer = new Handler();
 fadeTimer.postDelayed(fadeUi, 10000);

 fadeViews = new ArrayList<View>();
 fadeViews.add(gpsState);
 fadeViews.add(imageToggleView);
 fadeViews.add(locFixIcon);

 imageToggleView.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 if (DEBUG)
 Log.i(DEBUG_TAG, "Toggle clicked!");

 if (loadFirstMapPackFlag)
 loadFirstMapPackFlag = false;
 else
 loadFirstMapPackFlag = true;

 tilesOverlay.onDetach(mapView);
 mapView.getOverlayManager().remove(tilesOverlay);
 tilesOverlay = null;

 buildTilesLayer();

 if (DEBUG)
 Log.i(DEBUG_TAG, "Added Tiles Overlay!");
 mapView.getOverlayManager().add(0,tilesOverlay);

 mapView.invalidate();
 }
 });

 gpsState.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 showDialog(INFO_DIALOG);

 }
 });

 locFixIcon.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 if (lockPositionFlag){
 lockPositionFlag = false;
 } else {
 lockPositionFlag = true;
 Toast.makeText( getApplicationContext(), "Auf Standort zentrieren ", Toast.LENGTH_SHORT).show();

 Uri mapRequest = Settings.CONTENT_URI;
 Cursor c = getContentResolver().query(mapRequest, null, null, null, null);
 double lat = 0;
 double lon = 0;
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 lat = c.getDouble(c.getColumnIndex(Settings.LAST_LAT));
 lon = c.getDouble(c.getColumnIndex(Settings.LAST_LON));
 }
 }
 if (lat != 0 || lon != 0)
 mapController.setCenter(new GeoPoint(lat, lon));
 }
 }
 });

initializeFields();

 startService(new Intent(this,CartoDownloadService.class));

 ActionBarItem mapsIcon = getActionBar().newActionBarItem(NormalActionBarItem.class).setDrawable(getApplicationContext().getResources().getDrawable(R.drawable.kartenauswahl)).setContentDescription("karten");
 ActionBarItem placesIcon = getActionBar().newActionBarItem(NormalActionBarItem.class).setDrawable(getApplicationContext().getResources().getDrawable(R.drawable.set_waypoint)).setContentDescription("punkte");
 ActionBarItem quitIcon = getActionBar().newActionBarItem(NormalActionBarItem.class).setDrawable(getApplicationContext().getResources().getDrawable(R.drawable.quit_wb)).setContentDescription("beenden");
 getActionBar().addItem(placesIcon);
 getActionBar().addItem(mapsIcon);
 getActionBar().addItem(quitIcon);

getActionBar().setOnActionBarListener(new OnClickActionBarListener());

 Uri mapRequest = Settings.CONTENT_URI;
 Cursor c = getContentResolver().query(mapRequest, null, null, null, null);
 double lat = 48.21111;
 double lon = 16.378;
 int zoom = 13;
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 lat = c.getDouble(c.getColumnIndex(Settings.LAST_LAT));
 lon = c.getDouble(c.getColumnIndex(Settings.LAST_LON));
 zoom = c.getInt(c.getColumnIndex(Settings.LAST_ZOOM));
 }
 }

 lastLocation = new Location("Default");
 lastLocation.setLatitude(lat);
 lastLocation.setLongitude(lon);

 mapController.setZoom(zoom);
 lastLocation.setAccuracy(1001);
 mapController.setCenter(new GeoPoint(lat, lon));

 mapView.setMapListener(new MapListener() {

 @Override
 public boolean onZoom(ZoomEvent arg0) {
 if (lastLocation != null)
 setAccuracyMarker(lastLocation.getAccuracy());

 ContentValues values = new ContentValues();
 values.put(Settings.LAST_ZOOM, mapView.getZoomLevel());
 getContentResolver().update(Settings.CONTENT_URI, values, "", null);

 return false;
 }

 @Override
 public boolean onScroll(ScrollEvent arg0) {
 setMapCenterMarker();
 return false;
 }
 });

 LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
 mlocListener = new MyLocationListener(mapController);
 mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
 mlocManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, mlocListener);

 mapView.setBuiltInZoomControls(true);

 mapView.setMultiTouchControls(true);

 mapView.setLowPerformanceInterface(this);
 gpsState.setImageResource(R.drawable.gps_nein);

 if (savedInstanceState != null){
 loadFirstMapPackFlag = savedInstanceState.getBoolean(BUNDLE_TOGGLE);
 lockPositionFlag = savedInstanceState.getBoolean(BUNDLE_CENTER);
 }

 }

 @Override
 public void onLowMemory() {
 super.onLowMemory();

 }

 @Override
 protected void onPrepareDialog(int id, Dialog dialog) {
 switch (id) {
 case INFO_DIALOG:
 prepareInfoDialog(dialog);
 return;
 case MARKER_DIALOG:
 prepareMarkerDialog(dialog);
 return;
 default:
 return;
 }
 }

@Override
 protected Dialog onCreateDialog(int id) {
 switch (id) {
 case INFO_DIALOG:
 Dialog infoDialog = new Dialog(this);
 infoDialog.setContentView(R.layout.main_info_dialog);
 infoDialog.setTitle("Info");
 return infoDialog;

 case QUIT_DIALOG:
 AlertDialog.Builder builder = new Builder(this);
 builder.setMessage(R.string.quitDialogText).setCancelable(false).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 finish();
 }
 }).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 /* we do not do anything here */
 }
 });
 return builder.create();

 case MARKER_DIALOG:
 Dialog markerDialog = new Dialog(this);
 markerDialog.setContentView(R.layout.marker_info_dialog);
 markerDialog.setTitle("Marker Info");
 return markerDialog;

 default:
 return null;
 }
 }

@Override
 public boolean onOptionsItemSelected(MenuItem item) {
 if (DEBUG)
 Log.i(DEBUG_TAG, "Item selected: " + item.getItemId());
 switch (item.getItemId()) {
 case R.id.info:
 showDialog(INFO_DIALOG);
 return true;
 case R.id.preferences:
 return true;
 case R.id.quit:
 showDialog(QUIT_DIALOG);
 return true;
 default:
 return super.onOptionsItemSelected(item);
 }

 }

@Override
 public boolean onCreateOptionsMenu(Menu menu) {
 MenuInflater inflater = getMenuInflater();
 inflater.inflate(R.menu.map_manu, menu);
 return true;
 }

 @Override
 protected void onSaveInstanceState(Bundle outState) {
 outState.putInt(BUNDLE_SCROLLX, mapView.getScrollX());
 outState.putInt(BUNDLE_SCROLLY, mapView.getScrollY());
 outState.putInt(BUNDLE_ZOOM, mapView.getZoomLevel());
 outState.putBoolean(BUNDLE_TOGGLE, loadFirstMapPackFlag);
 outState.putBoolean(BUNDLE_CENTER, lockPositionFlag);
 super.onSaveInstanceState(outState);
 }

@Override
 protected void onRestoreInstanceState(Bundle savedInstanceState) {
 if (mapView != null && savedInstanceState != null){
 if (savedInstanceState.getInt(BUNDLE_ZOOM) != 0)
 mapView.getController().setZoom(savedInstanceState.getInt(BUNDLE_ZOOM));
 if (savedInstanceState.getInt(BUNDLE_SCROLLX) != 0 && savedInstanceState.getInt(BUNDLE_SCROLLY) != 0)
 mapView.scrollTo(savedInstanceState.getInt(BUNDLE_SCROLLX), savedInstanceState.getInt(BUNDLE_SCROLLY));
 }
 super.onRestoreInstanceState(savedInstanceState);
 }

@Override
 protected void onDestroy() {
 stopService(new Intent(getApplicationContext(), CartoDownloadService.class));
 LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
 mlocManager.removeUpdates(mlocListener);

 mapView = null;

 super.onDestroy();
 }

@Override
 protected void onPause() {
 super.onPause();
 }

@Override
 protected void onResume() {
 super.onResume();
 }

@Override
 protected void onStart() {
MapTileProviderBase tilesource = new MapTileProviderBasic(getApplicationContext(), TileSourceFactory.MAPNIK);
 tilesource.setTileRequestCompleteHandler(new SimpleInvalidationHandler(mapView));
 mapView.getOverlayManager().setTilesOverlay(new TilesOverlay(tilesource, new DefaultResourceProxyImpl(getApplicationContext())));

 buildTilesLayer();
 if (DEBUG)
 Log.i(DEBUG_TAG, "Added Tiles Overlay!");
 mapView.getOverlayManager().add(tilesOverlay);

 buildWaypointLayer();
 mapView.getOverlayManager().add(waypointOverlay);

 positionOverlay = new aItemizedOverlay(getApplicationContext(), new ArrayList<OverlayItem>(), null);
 mapView.getOverlayManager().add(positionOverlay);
 setPositionMarker();
 if (lastLocation != null)
 setAccuracyMarker(lastLocation.getAccuracy());

 markerOverlay = new aItemizedOverlay(getApplicationContext(), new ArrayList<OverlayItem>(), null);
 mapView.getOverlayManager().add(markerOverlay);
 setMapCenterMarker();

 ScaleBarOverlay mScaleBarOverlay = new ScaleBarOverlay(this);
 mScaleBarOverlay.setScaleBarOffset(mScaleBarOverlay.xdpi / 2, 20);
 mScaleBarOverlay.enableScaleBar();

 mapView.getOverlayManager().add(mScaleBarOverlay);

 mapView.invalidate();
 super.onStart();
 }

@Override
 protected void onStop() {

 if (DEBUG)
 Log.i(DEBUG_TAG, "onStop executed!");

 mapView.getOverlayManager().onDetach(mapView);

 while (mapView.getOverlayManager().size() > 0) {
 mapView.getOverlayManager().remove(0);
 }

super.onStop();
 }

 @Override
 public void onAnimationEnd(Animation animation) {
 if (uiVisible){
 uiVisible = false;
 for (View element : fadeViews) {
 element.setVisibility(View.INVISIBLE);
 }

 } else {
 fadeTimer.removeCallbacks(fadeUi);
 fadeTimer.postDelayed(fadeUi, 10000);
 uiVisible = true;
 }

 if (pendingAnimation) {
 pendingAnimation = false;
 for (View element : fadeViews) {
 element.startAnimation(fadeIn);
 }
 } else
 fadeAnimationRunning = false;
 }

@Override
 public void onAnimationRepeat(Animation animation) {

 }

@Override
 public void onAnimationStart(Animation animation) {
 for (View element : fadeViews) {
 element.setVisibility(View.VISIBLE);
 }
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {

 if (DEBUG)
 Log.i(DEBUG_TAG, "Touch Event on Map, Visible: " + uiVisible + " / Fading: " + fadeAnimationRunning);
 if (!uiVisible) {
 if (!fadeAnimationRunning){
 fadeAnimationRunning = true;
 for (View element : fadeViews) {
 element.startAnimation(fadeIn);
 }
 if (DEBUG)
 Log.i(DEBUG_TAG, "Fade Event Started");
 }
 } else {
 if (fadeAnimationRunning)
 pendingAnimation = true;
 fadeTimer.removeCallbacks(fadeUi);
 fadeTimer.postDelayed(fadeUi, 3000);
 }

 return super.onTouchEvent(event);
 }

 @Override
 public void onLowPerformance() {
 if (DEBUG)
 Log.i(DEBUG_TAG, "Low Performance reported from MapView");
 }
private void prepareMarkerDialog(final Dialog dialog){

 TextView name = (TextView) dialog.findViewById(R.id.value_name);
 TextView desc = (TextView) dialog.findViewById(R.id.value_desc);
 TextView lat = (TextView) dialog.findViewById(R.id.value_lat);
 TextView lon = (TextView) dialog.findViewById(R.id.value_lon);
 TextView date = (TextView) dialog.findViewById(R.id.value_date);
 TextView time = (TextView) dialog.findViewById(R.id.value_time);
 Button close = (Button)dialog.findViewById(R.id.close);

 if (lastTappedMarker != null){

 Cursor c = getContentResolver().query(Uri.withAppendedPath(Markers.CONTENT_URI, "/" + lastTappedMarker.getDesc()), null, null, null, null);
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 desc.setText(c.getString(c.getColumnIndex(Markers.NOTIZ)));
 date.setText(c.getString(c.getColumnIndex(Markers.DATUM)));
 time.setText(c.getString(c.getColumnIndex(Markers.ZEIT)));
 }
 }
 c.close();
 name.setText(lastTappedMarker.getName());
 lat.setText(formatNumber(Math.round(lastTappedMarker.getLatE6()*1E-3)*1E-3, "0.0##"));
 lon.setText(formatNumber(Math.round(lastTappedMarker.getLonE6()*1E-3)*1E-3, "0.0##"));

 }

 close.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 dialog.dismiss();

 }
 });
 }

 private void prepareInfoDialog(final Dialog dialog){
 if (DEBUG)
 Log.i(DEBUG_TAG, "Dialog prepared");

 infoBox_provider_accuracy = (TextView)dialog.findViewById(R.id.provider_accuracy_value);
 infoBox_gps_accuracy = (TextView)dialog.findViewById(R.id.gps_accuracy_value);
 infoBox_lat = (TextView)dialog.findViewById(R.id.latitude_value);
 infoBox_lon = (TextView)dialog.findViewById(R.id.longitude_value);
 infoBox_altitude = (TextView)dialog.findViewById(R.id.altitude_value);
 infoBox_speed = (TextView)dialog.findViewById(R.id.speed_value);
 TextView zoomLevel = (TextView)dialog.findViewById(R.id.zoomlevel_value);
 Button infoBox_close = (Button)dialog.findViewById(R.id.close);

 zoomLevel.setText(String.valueOf(mapView.getZoomLevel()));
 infoBox_lon.setText(formatNumber(Math.round(mapView.getMapCenter().getLongitudeE6()*1E-3)*1E-3,"0.0##"));
 infoBox_lat.setText(formatNumber(Math.round(mapView.getMapCenter().getLatitudeE6()*1E-3)*1E-3, "0.0##"));
 infoBox_provider_accuracy.setText(R.string.notavailable);
 infoBox_gps_accuracy.setText(R.string.notavailable);
 infoBox_altitude.setText(R.string.notavailable);
 infoBox_speed.setText(R.string.notavailable);

 if (lastLocation != null) {
 if (lastLocation.getProvider().equals(LocationManager.GPS_PROVIDER))
 infoBox_gps_accuracy.setText(String.valueOf(lastLocation.getAccuracy()));
 else if (lastLocation.getProvider().equals(LocationManager.NETWORK_PROVIDER))
 infoBox_provider_accuracy.setText(String.valueOf(lastLocation.getAccuracy()));

 infoBox_altitude.setText(String.valueOf(Math.round(lastLocation.getAltitude())));
 infoBox_speed.setText(String.valueOf(lastLocation.getSpeed()*3.6));
 }

 infoBox_close.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 dialog.dismiss();
 }
 });
 }

 private void buildWaypointLayer(){
 Cursor c;

 OnItemGestureListener<OverlayItem> pOnItemGestureListener = new myItemGestureListener<OverlayItem>();
 waypointOverlay = new aItemizedOverlay(getApplicationContext(), new ArrayList<OverlayItem>(), pOnItemGestureListener);

 Resources res = getResources();

 c = getContentResolver().query(Markers.CONTENT_URI, null, null, null, null);
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 do{
 String name = c.getString(c.getColumnIndex(Markers.NAME));
 int latE6 = c.getInt(c.getColumnIndex(Markers.LATITUDE));
 int lonE6 = c.getInt(c.getColumnIndex(Markers.LONGITUDE));
 if (c.getInt(c.getColumnIndex(Maps.AKTIV)) == 1){
 Drawable marker = res.getDrawable(R.drawable.waypoint);
 OverlayItem markerItem = new OverlayItem(name,c.getString(c.getColumnIndex(Markers._ID)),new GeoPoint(latE6, lonE6));

 markerItem.setMarker(marker);
 markerItem.setMarkerHotspot(HotspotPlace.LOWER_LEFT_CORNER);

 waypointOverlay.addItem(markerItem);
 }
 } while (c.moveToNext());
 }
 }
 c.close();
 }

 private void setPositionMarker(){
 if (lastLocation != null && mapView != null){
 if (DEBUG)
 Log.i(DEBUG_TAG, "setting Position marker to last location...");

 if (positionMarker != null)
 positionOverlay.removeItem(positionMarker);

Resources res = getResources();
 positionMarkerDrawable = (Drawable) res.getDrawable(R.drawable.gps_position_animated);

 positionMarker = null;
 positionMarker = new OverlayItem("Position Marker","Description of my Marker",new GeoPoint(lastLocation.getLatitude(), lastLocation.getLongitude()));
 positionMarker.setMarker(positionMarkerDrawable);
 positionMarker.setMarkerHotspot(HotspotPlace.CENTER);
 positionOverlay.addItem(positionMarker);
 mapView.invalidate();

 if (DEBUG)
 Log.i(DEBUG_TAG, "setting Position marker... finished");

 }

}

 private void setMapCenterMarker(){
 if (mapView != null){
 markerOverlay.removeAllItems();
 Resources res = getResources();
 Drawable posMarker = res.getDrawable(R.drawable.display_mitte);

 OverlayItem mapCenterMarker = new OverlayItem("Map Center Marker","Description of my Marker",new GeoPoint(mapView.getMapCenter().getLatitudeE6()*1E-6, mapView.getMapCenter().getLongitudeE6()*1E-6));
 mapCenterMarker.setMarker(posMarker);
 mapCenterMarker.setMarkerHotspot(HotspotPlace.CENTER);
 markerOverlay.addItem(mapCenterMarker);

 mapView.invalidate();
 }
 }

 private void setAccuracyMarker(float accuracy){
 if (lastLocation != null && mapView != null){
 if (DEBUG)
 Log.i(DEBUG_TAG, "setting Accuracy marker...");
 if (accuracyMarker != null)
 positionOverlay.removeItem(accuracyMarker);

Resources res = getResources();

 if ((mapView.getZoomLevel() == 11 && accuracy > 500 && accuracy <= 1000) ||
 (mapView.getZoomLevel() == 12 && accuracy > 250 && accuracy <= 1000) ||
 (mapView.getZoomLevel() == 13 && accuracy > 100 && accuracy <= 1000) ||
 (mapView.getZoomLevel() == 14 && accuracy > 50 && accuracy <= 1000) ||
 (mapView.getZoomLevel() == 15 && accuracy > 25 && accuracy <= 1000))
 {
 Drawable marker = res.getDrawable(R.drawable.gps_genauigkeit_26);
 if (mapView.getZoomLevel() == 15 && accuracy > 500)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_420);
 else if (mapView.getZoomLevel() == 15 && accuracy > 250)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_210);
 else if (mapView.getZoomLevel() == 15 && accuracy > 100)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_105);
 else if (mapView.getZoomLevel() == 15 && accuracy > 75)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_42);
 else if (mapView.getZoomLevel() == 15 && accuracy > 50)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_31);
 else if (mapView.getZoomLevel() == 15 && accuracy > 0)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_21);
 if (mapView.getZoomLevel() == 14 && accuracy > 500)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_210);
 else if (mapView.getZoomLevel() == 14 && accuracy > 250)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_105);
 else if (mapView.getZoomLevel() == 14 && accuracy > 100)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_52);
 else if (mapView.getZoomLevel() == 14 && accuracy > 75)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_21);
 else if (mapView.getZoomLevel() == 14 && accuracy > 50)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_16);
 if (mapView.getZoomLevel() == 13 && accuracy > 500)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_105);
 else if (mapView.getZoomLevel() == 13 && accuracy > 250)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_52);
 if (mapView.getZoomLevel() == 12 && accuracy > 500)
 marker = res.getDrawable(R.drawable.gps_genauigkeit_52);

 accuracyMarker = new OverlayItem("Accuracy Marker","Description of my Marker",new GeoPoint(lastLocation.getLatitude(), lastLocation.getLongitude()));
 accuracyMarker.setMarker(marker);
 accuracyMarker.setMarkerHotspot(HotspotPlace.CENTER);
 positionOverlay.addItem(accuracyMarker);
 }

 if (accuracy <= 25)
 gpsState.setImageResource(R.drawable.gps_ja);
 else if (accuracy <= 100)
 gpsState.setImageResource(R.drawable.gps_schlecht);
 else
 gpsState.setImageResource(R.drawable.gps_nein);

 mapView.invalidate();

 if (DEBUG)
 Log.i(DEBUG_TAG, "setting Accuracy marker... finished");
 }
 }

 private void initializeFields(){
 loadFirstMapPackFlag = true;
 lockPositionFlag = false;

 mapController = mapView.getController();
 }

 private void buildTilesLayer(){
 List<String> overlayArchiveResources = new ArrayList<String>(1);

 Uri mapRequest = at.ac.univie.carto.contentprovider.CartoContentProvider.Maps.CONTENT_URI;
 Cursor c = getContentResolver().query(mapRequest, null, null, null, null);
 boolean mapLeftOut = false;
 if (c != null && c.getCount() > 0){
 if (c.moveToFirst()) {
 do{
 int anzahl = c.getInt(c.getColumnIndex(Maps.DATEIANZAHL));
 String dateiPfad = c.getString(c.getColumnIndex(Maps.DATEIPFAD));
 String dateiName = c.getString(c.getColumnIndex(Maps.DATEINAME));
 if (c.getInt(c.getColumnIndex(Maps.AKTIV)) == 1){
 if (!mapLeftOut && !loadFirstMapPackFlag){
 mapLeftOut = true;
 } else {
 for (int i = 0; i < anzahl; i++) {
 Log.i("map Controller", "Added Map " + dateiPfad + dateiName + i + ".zip");
 overlayArchiveResources.add(dateiPfad + dateiName + i + ".zip");
 }
 }
 }

 } while (c.moveToNext());
 }
 }
 c.close();
 List<MapTileModuleProviderBase> overlayFileProvider = new ArrayList<MapTileModuleProviderBase>(2);
 File overlayFile;
 myTileSource overlayFileTileSource = null;
 IArchiveFile[] overlayFileArchive = new IArchiveFile[1];
 for (String path : overlayArchiveResources) {
 overlayFile = new File(path);
 if (overlayFile.exists())
 overlayFileArchive[0] = ArchiveFileFactory.getArchiveFile(overlayFile);
 else
 continue;
 overlayFile = null;
 overlayFileTileSource = new myTileSource("map", null, 8, 16, 256, ".jpg");
 overlayFileProvider.add(new MapTileFileArchiveProvider(new SimpleRegisterReceiver(getApplicationContext()), overlayFileTileSource, overlayFileArchive));
 }
 overlayFileArchive = null;
 MapTileModuleProviderBase[] overlayFileProvider2 = new MapTileModuleProviderBase[overlayFileProvider.size()];
 MapTileProviderArray overlayFileProviderArray1 = new MapTileProviderArrayExtended(overlayFileTileSource,null, overlayFileProvider.toArray(overlayFileProvider2));
 overlayFileProviderArray1.setTileRequestCompleteHandler(mapView.getTileRequestCompleteHandler());
 tilesOverlay = new TilesOverlay(overlayFileProviderArray1, getApplicationContext());
 tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
 overlayFileProvider = null;
 overlayFileProvider2 = null;
 overlayFileProviderArray1 = null;

}

 private String formatNumber(double Value, String formatString){
 DecimalFormat formatter = new DecimalFormat(formatString);
 return formatter.format(Value);
 }

 private class OnClickActionBarListener implements OnActionBarListener {

@Override
 public void onActionBarItemClicked(int position) {
 if (position == 2){
 showDialog(QUIT_DIALOG);
 } else if (position == 1){
 Intent mapSelect = new Intent().setComponent(new ComponentName(getApplicationContext(), MapSelect.class));
 startActivity(mapSelect);
 } else if (position == 3){
 Intent waypointSelect = new Intent().setComponent(new ComponentName(getApplicationContext(), WaypointSelect.class));
 startActivity(waypointSelect);
 } else if (position == 0){
 Intent waypointAdd = new Intent().setComponent(new ComponentName(getApplicationContext(), WaypointAdd.class));
 int[] location = new int[2];
 location[0] = mapView.getMapCenter().getLatitudeE6();
 location[1] = mapView.getMapCenter().getLongitudeE6();
 waypointAdd.putExtra(R.string.app_prefix + ".location", location);
 startActivity(waypointAdd);
 }
 }

 }

 public class myTileSource extends BitmapTileSourceBase {

public myTileSource(String aName, string aResourceId, int aZoomMinLevel,
 int aZoomMaxLevel, int aTileSizePixels, String aImageFilenameEnding) {
 super(aName, aResourceId, aZoomMinLevel, aZoomMaxLevel, aTileSizePixels,
 aImageFilenameEnding);
 }

}

 public class myItemGestureListener<T extends OverlayItem> implements OnItemGestureListener<T> {

@Override
 public boolean onItemSingleTapUp(int index, T item) {
 if (DEBUG)
 Log.i(DEBUG_TAG, "Item clicked: " + item.getTitle());
 lastTappedMarker = new Marker();
 lastTappedMarker.setName(item.mTitle);
 lastTappedMarker.setDesc(item.mDescription);
 lastTappedMarker.setLatE6(item.mGeoPoint.getLatitudeE6());
 lastTappedMarker.setLonE6(item.mGeoPoint.getLongitudeE6());
 showDialog(MARKER_DIALOG);
 return false;
 }

@Override
 public boolean onItemLongPress(int index, T item) {
 return false;
 }

&nbsp;

}

 public class MyLocationListener implements LocationListener
 {
 private MapController mapController;
 private long lastGPSSignal;
 private long lastNetworkSignal;

 public MyLocationListener(MapController controller){
 this.lastGPSSignal = 0;
 this.lastNetworkSignal = 0;
 this.mapController = controller;
 }
 @Override
 public void onLocationChanged(Location loc)
 {
 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER))
 lastGPSSignal = System.currentTimeMillis();
 if (loc.getProvider().equals(LocationManager.NETWORK_PROVIDER))
 lastNetworkSignal = System.currentTimeMillis();

 if (DEBUG)
 Log.i(DEBUG_TAG, "new Location from Provider " + lastLocation.getProvider() + " received with acc " + lastLocation.getAccuracy() + " for InfoBoxField: " + infoBox_provider_accuracy);
 lastLocation = loc;
 if (lockPositionFlag)
 this.mapController.setCenter(new GeoPoint(loc.getLatitude(), loc.getLongitude()));

 if (infoBox_gps_accuracy != null && lastLocation.getProvider().equals(LocationManager.GPS_PROVIDER) && lastLocation != null)
 infoBox_gps_accuracy.setText(String.valueOf(lastLocation.getAccuracy()));
 if (infoBox_provider_accuracy != null && lastLocation.getProvider().equals(LocationManager.NETWORK_PROVIDER) && lastLocation != null)
 infoBox_provider_accuracy.setText(String.valueOf(lastLocation.getAccuracy()));
 if (lastLocation.getProvider().equals(LocationManager.NETWORK_PROVIDER)){
 if (lastGPSSignal == 0 || (System.currentTimeMillis() - lastGPSSignal) > GPSTTIMEOUT) {
 if (infoBox_lat != null && mapView != null)
 infoBox_lat.setText(formatNumber(Math.round(mapView.getMapCenter().getLatitudeE6()*1E-3)*1E-3, "0.0##"));
 if (infoBox_lon != null && mapView != null)
 infoBox_lon.setText(formatNumber(Math.round(mapView.getMapCenter().getLongitudeE6()*1E-3)*1E-3, "0.0##"));
 }
 } else if (lastLocation.getProvider().equals(LocationManager.GPS_PROVIDER)){
 if (infoBox_lat != null && mapView != null)
 infoBox_lat.setText(formatNumber(Math.round(mapView.getMapCenter().getLatitudeE6()*1E-3)*1E-3, "0.0##"));
 if (infoBox_lon != null && mapView != null)
 infoBox_lon.setText(formatNumber(Math.round(mapView.getMapCenter().getLongitudeE6()*1E-3)*1E-3, "0.0##"));
 }
 if (infoBox_speed != null && mapView != null)
 infoBox_speed.setText(formatNumber(lastLocation.getSpeed()*3.6, "0.0##"));
 if (infoBox_altitude != null && mapView != null)
 infoBox_altitude.setText(String.valueOf(Math.round(lastLocation.getAltitude())));

 ContentValues values = new ContentValues();
 values.put(Settings.LAST_LAT, loc.getLatitude());
 values.put(Settings.LAST_LON, loc.getLongitude());
 getContentResolver().update(Settings.CONTENT_URI, values, "", null);

setAccuracyMarker(loc.getAccuracy());
 setPositionMarker();

 }
 @Override
 public void onProviderDisabled(String provider)
 {
 gpsState.setImageResource(R.drawable.gps_nein);
 }

@Override
 public void onProviderEnabled(String provider)
 {

}

@Override
 public void onStatusChanged(String provider, int status, Bundle extras)
 {

}

}

 private class aItemizedOverlay extends ItemizedIconOverlay<OverlayItem>{

public aItemizedOverlay(
 Context pContext,
 List<OverlayItem> pList,
 org.osmdroid.views.overlay.ItemizedIconOverlay.OnItemGestureListener<OverlayItem> pOnItemGestureListener) {
 super(pContext, pList, pOnItemGestureListener);
 }

@Override
 public boolean onTouchEvent(MotionEvent event, MapView mapView) {
 lockPositionFlag = false;
 return false;
 }

 }

}
<pre>

The next activity i’ll show is the Map Selection. There we can activate and deactivate maps, download maps and delete maps.

, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

3 Kommentare