TourGuide - Virtual Sightseeing

SDK Version: 

This application is a simple application with a Spinner select a location and view that location on a MapView. Click here to download the complete source.

Here is what this TourGuide application looks like:

The main class "TourGuide" is a MapActivity. Only a MapActivity is permitted to create a MapView, but for some reason, you are not permitted to use a MapView XML element. However, I found a workaround in this post on android-developers. If you use a <MapView> element you will get an error, but if you use a <view> and separately specify the class as "" it will work.

Here is the main.xml layout file that we'll use for this application:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android=""
  3.     android:layout_width="fill_parent"
  4.     android:layout_height="fill_parent">
  6.         <view class=""
  7.                 android:id="@+id/map"
  8.                 android:layout_width="fill_parent"
  9.                 android:layout_height="fill_parent"/>
  11.         <Spinner android:id="@+id/spinner1"
  12.                 android:layout_alignParentTop="true"
  13.                 android:layout_width="fill_parent"
  14.                 android:layout_height="wrap_content"
  15.                 android:drawSelectorOnTop="true"
  16.                 android:paddingTop="10dip"
  17.                 android:paddingBottom="10dip" />
  19. </RelativeLayout>

Our layout is a RelativeLayout with a MapView that fills the whole screen, and a spinner floating on top of it at the top of the screen. Now we must create our MapActivity in

  1. public class TourGuide extends MapActivity {
  3.         private String[][] locations = { { "Area 51", "-115.800155,37.248040&quot; },
  4.                         { "Bill Gates' house", "-122.242135,47.627787&quot; },
  5.                         { "Shepshed Dynamo Football Grounds", "-1.286913,52.774472"; },
  6.                         { "Michael Jackson's Neverland Ranch", "-120.088012,34.745527&quot; },
  7.                         { "Leaning Tower of Pisa", "10.396473,43.723002"; },
  8.                         { "Airplane Graveyard", "-110.834026,32.150899&quot; },
  9.                         { "Grand Canyon", "-112.298641,36.142788&quot; },
  10.                         { "Lake Kariba", "27.990417,-17.235252&quot; },
  11.                         { "White House", "-77.036519,38.897605&quot; },
  12.                         { "World Trade Center site", "-74.012253,40.711641&quot; },
  13.                         { "Las Vegas Strip", "-115.162296,36.133347&quot; } };
  15.         private Spinner spinner;
  16.         private MapView map;
  17.         private MapController mc;
  19.         @Override
  20.         public void onCreate(Bundle icicle) {
  21.                 super.onCreate(icicle);
  22.                 setContentView(R.layout.main);
  24.                 spinner = (Spinner) this.findViewById(;
  25.                 map = (MapView) findViewById(;
  26.                 mc = map.getController();
  28.                 ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
  29.                                 this, android.R.layout.simple_spinner_dropdown_item);
  31.                 for (int i = 0; i < locations.length; i++)
  32.                         adapter.addObject(locations[i][0]);
  34.                 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
  35.                 spinner.setAdapter(adapter);
  36.                 spinner.setOnItemSelectedListener(selectListener);
  37.                 gotoSelected();
  38.         }
  40.         private OnItemSelectedListener selectListener = new OnItemSelectedListener() {
  41.                 public void onItemSelected(AdapterView parent, View v, int position, long id) {
  42.                         gotoSelected();
  43.                 }
  44.                 public void onNothingSelected(AdapterView arg0) {}
  45.         };

So first I've just defined an array of Strings called location starting on line 18. It's a 2d array with each entry having the label for the location and the latitude/longitude. I grabbed these from 's most popular destinations. The exact coordinates can be found in the kml file for each one.

In the onCreate() function we first initialize our MapView and Spinner. After that we create an ArrayAdapter to use with the Spinner and add each label from the locations array to this ArrayAdapter. Once it's filled in we set it as the ArrayAdapter for the Spinner and then call gotoSelected() to move the map to the currently selected item (Area 51 when you first start this app in this example). Finally we setup the Spinner's OnItemSelectdListener so that it will call gotoSelected() when a new item is selected.

Here is the gotoSelected() function that will move our map to the correct location:

  1. public void gotoSelected() {
  2.         int pos = spinner.getSelectedItemPosition();
  4.         String[] loc = locations[pos][1].split(",");
  5.         double lat = Double.parseDouble(loc[1]);
  6.         double lon = Double.parseDouble(loc[0]);
  8.         Point p = new Point((int) (lat * 1E6), (int) (lon * 1E6));
  9.         mc.animateTo(p);
  10.         mc.zoomTo(18);
  12.         if (!map.isSatellite())
  13.                 map.toggleSatellite();
  15.         map.invalidate();
  16. }

To go to a location we must create a Point using the latitude and longitude in microdegrees (10^-6). So we get the coordinates from the locations array string for the selected object and split it to get the seperate longitude and latitude as a double. Once we have these we must multiply each one by 1,000,000 to get it's value in microdegrees. Now that we have the Point object we can use a MapController to go to our point using animateTo(Point) and a zoom level of 18 using zoomTo(Int). Finally we make sure that we are showing satellite view instead of map view, and we call map.invalidate() to force it to redraw.

With this you would be able to go view different objects and pan around using the touchscreen. But pressing "I" or "O" doesn't zoom like it normally does, so we must handle those keys to allow the user to zoom in and out. We can simply override the onKeyDown function, and here is that function:

  1. @Override
  2. public boolean onKeyDown(int keyCode, KeyEvent event) {
  3.         switch (keyCode) {
  4.         case KeyEvent.KEYCODE_I:
  5.                 mc.zoomTo(map.getZoomLevel() + 1);
  6.                 break;
  7.         case KeyEvent.KEYCODE_O:
  8.                 mc.zoomTo(map.getZoomLevel() - 1);
  9.                 break;
  10.         }
  11.         return super.onKeyDown(keyCode, event);
  12. }

Very simple switch statement here, if the user pressed "I" we zoom in, and they press "O" we zoom out.

I hope you enjoyed this simple application to demonstrate using a MapView. Obviously it's not ideal to just have a bunch of hard-coded locations, but it could be extended to pull and parse some XML from a source on the internet or could be populated by performing a Search on keywords. If you have any questions/comments/suggestions check out the tutorials forum.

Good luck in the challenge!!