A Kindle Fire Amazon Maps API Tutorial

Revision as of 20:24, 20 May 2013 by Neil (Talk | contribs) (New page: <table border="0" cellspacing="0" width="100%"> <tr> <td width="20%">Previous<td align="center">[[Kindle Fire Development Essentials...)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Revision as of 20:24, 20 May 2013 by Neil (Talk | contribs) (New page: <table border="0" cellspacing="0" width="100%"> <tr> <td width="20%">Previous<td align="center">[[Kindle Fire Development Essentials...)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
PreviousTable of ContentsNext
Working with the Amazon Maps API on the Kindle FireMarking Android Map Locations using Amazon Map Overlays


<google>BUY_KINDLE_FIRE</google>


The previous chapter covered a considerable amount of ground relating to the implementation of maps in Kindle Fire based Android applications using the Amazon Maps API. In this chapter, we will take this knowledge and use it to create an example application that uses this API.

This chapter makes the assumption that you have read the previous chapter and have already downloaded and installed the Amazon Mobile SDK package and taken the necessary steps to obtain the MD5 fingerprint for your development environment.

About the Example Map Application

The application created in this chapter will consist of two activities. The user will enter an address into a text field in the first activity screen and then touch a button. This will trigger the second activity, which will display a map centered at the location corresponding to the previously entered address. In the next chapter, this example will be extended to use an overlay to mark the specified location on the map using a custom drawable image.

Creating and Preparing the MapExample Project

In steps that should by now be more than familiar, launch Eclipse and create a new Android Application project named MapExample using the appropriate Android SDK versions and package name and including a blank activity named MapExampleActivity with a corresponding layout named activity_map_example.

Right click on the MapExample entry in the Eclipse Package Explorer panel and select Properties from the resulting menu. Within the Properties dialog, select the Java Build Path category from the left hand panel and within the Java Build Path panel select the Libraries tab and click on the Add External JARs… button. In the JAR selection dialog, navigate to the following location (where <sdk path> is replaced by the location on your file system where the Amazon Mobile SDK was installed in the previous chapter):

<sdk path>/Maps/lib

From within the libs directory, select the amazonmaps jar file. At time of writing, this file is named amazonmaps-1.0.2.jar but may have been superseded since then by a newer version. Once selected, click on the Open button to add the JAR file to the project. Once added, it should be listed in the Java Build Path panel. Assuming the JAR file is now listed, click on OK to close the Properties dialog.


Registering the Application in the Amazon Mobile App Distribution Portal

The next step is to register the application in the Amazon distribution portal and input the MD5 debug fingerprint to enable Map support. To achieve this, open a web browser and navigate to the following URL:

https://developer.amazon.com/welcome.html

Once logged in, click on the Add a New App button located within the dashboard panel. Within the New App Submission screen, enter the mandatory information (those fields marked by a red asterisk) before clicking on the Save button.

Once the app has been added, select it from the dashboard panel to view the details of the submission. Within the application details screen will be a link labeled Maps. Click on this link and in the resulting screen, click on the Add a Debug Registration button. When prompted, enter the package name for the application exactly as it appears within the project AndroidManifest.xml file (for example com.example.mapexample) and then cut and paste the MD5 fingerprint into the Developer Signature field before clicking on the Submit button.

Modifying the Android Manifest File

The final preparatory step before starting to develop the application is to modify the project manifest file to enable maps support. Within the Package Explorer panel, double click on the AndroidManifest.xml file and modify it to add the appropriate directives:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:amazon="http://schemas.amazon.com/apk/res/android"
    package="com.example.mapexample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-permission android:name= "android.permission.INTERNET" />
    <uses-permission android:name= "android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION" />
    
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <amazon:enable-feature android:name="com.amazon.geo.maps" android:required="false" />
        <activity
            android:name="com.example.mapexample.MapExampleActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 

With the application configured for maps support, it is now time to begin developing the application.

Adding the Map View Activity

The completed application is going to comprise two activities. One activity will be presented to the user when the application launches and will provide the user with the ability to enter an address and touch a button. The second activity will contain a Map View that will be displayed and centered on the designated address when the user touches the button in the first activity.

Within the Eclipse Package Explorer panel, right-click on the MapExample project name and select New -> Class from the resulting menu. Click within the Package: field and press ctrl-space to display a list of package names associated with the project. Double click to select the correct package (for example com.example.mapexample).

Within the Name: field, enter MyMapView as the class name before clicking on the Browse…button to the right of the Superclass field. Because this class is going to be required to display a MapView instance, the activity must be subclassed from MapActivity, instead of the usual Activity class. As such, enter MapActivity into the Choose a type: field of the Superclass Selection dialog and double click on the MapActivity – com.amazon.geo.maps entry to select it as the superclass for this new class. On returning to the New Java Class dialog, click on Finish to create the new class.

At this point, we have a class to represent the map presentation activity but no user interface layout to go with it. To address this, right-click on the MapExample project name once again, this time selecting the New -> Android XML file menu option. Within the resulting New Android XML File dialog, name the file my_map_view_layout.xml and change the root element selection to RelativeLayout.

When the user touches the button on the first activity, this second activity will be launched by issuing an explicit intent. In order for the MyMapView activity to be discoverable by the intent resolution system, it will need to be declared within the application’s manifest. Edit the AndroidManifest.xml file for the application once again and modify it to add this declaration:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:amazon="http://schemas.amazon.com/apk/res/android"
    package="com.example.mapexample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-permission android:name= "android.permission.INTERNET" />
    <uses-permission android:name= "android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name= "android.permission.ACCESS_FINE_LOCATION" />
    
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <amazon:enable-feature android:name="com.amazon.geo.maps" android:required="false" />
        <activity
            android:name="com.example.mapexample.MapExampleActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="MyMapView"
            android:label="MyMapView" >
        </activity>
    </application>
</manifest>

Adding the MapView Object

With the class and layout created for displaying the map view to the user, the next logical step is to add the MapView instance to the layout file. Locate the res -> layout -> my_map_view_layout.xml file within the Package Explorer panel and double click on it to load it into the editing panel. Select the my_map_view_layout.xml tab beneath the Graphical Layout tool to display the XML and add a MapView instance so that the XML reads as follows:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.amazon.geo.maps.MapView
       android:id="@+id/mapview"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:clickable="true"
       android:enabled="true" />

</RelativeLayout>

Once the map view has been added, save the XML file and then load the MyMapView.java file into the editing panel. Add an onCreate() method to this class to inflate the user interface layout when the activity is launched:

package com.example.mapexample;

import android.os.Bundle;
import com.amazon.geo.maps.MapActivity;

public class MyMapView extends MapActivity {

	public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_map_view_layout);
	}
	
	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}
}

Designing the User Interface for the MapExampleActivity Class

Locate and double click on the res -> layout -> activity_map_example.xml file and, using the Graphical Layout tool, delete the default “Hello world!” TextView object. With a clean user interface layout, drag and drop a Button view onto the layout canvas and position it so that it is centered both horizontally and vertically within the parent layout manager view. Change the text on the button to read “Find Location”. With the button positioned, drag and drop an Address EditText view so that it is positioned above the Button view as illustrated in Figure 41-1:


The UI for an example Amazon Maps App

Figure 41-1


When the button is touched by the user we want a method named showMap() to be called. This will require an onClick property within the XML layout file. Within Eclipse, therefore, switch from the Graphical Layout tool to the XML editing view and add the onClick property to the button element. Once completed, the XML for the layout should read as follows (allowing for differences in the positioning of the EditText view and the name assigned to your string resource):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MapExampleActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:onClick="showMap"
        android:text="@string/find_text" />

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/button1"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="36dp"
        android:ems="10"
        android:inputType="textPostalAddress" >

        <requestFocus />
    </EditText>

</RelativeLayout>

Save the layout file before moving to the next step.

Checking for Maps Support

Before attempting to display a map, the application first needs to verify that it is running on a device that supports the Amazon Map API. To achieve this we will add a method named hasMapSupport() to the MapExampleActivity.java file and call it from the onCreate() method of that class. In the event that maps are not supported, the “Find Location” button will need to be disabled:

package com.example.mapexample;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;

public class MapExampleActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_map_example);
		
		Button findButton = (Button) findViewById(R.id.button1);
		
		if (!hasMapSupport())
			findButton.setEnabled(false);	
	}

	public boolean hasMapSupport()
	{
		boolean result = false;
		try {
		     Class.forName( "com.amazon.geo.maps.MapView" );
		     result = true ;
		}
		catch (Exception e) {} 
		return result;
	}
.
.
}

Launching the Intent

When the user touches the button in the user interface, a method named showButton() will now be called. This method, once implemented, will be required to perform the following tasks:

1. Extract the address string from the EditText view.

2. Use Geocoding to convert the address into longitude and latitude.

3. Create an Intent object.

4. Add the Address object for the converted address as data to the Intent object.

5. Start the intent to launch the map view activity. With these five objectives in mind, locate and edit the MapExampleActivity.java file to add the showMap() method as outlined in the following listing:

package com.example.mapexample;

import java.io.IOException;
import java.util.List;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;
import android.view.View;
import android.content.Intent;
import android.widget.EditText;
import android.location.Geocoder;
import android.location.Address;

public class MapExampleActivity extends Activity {
.
.
.
public void showMap(View view) throws IOException {
    	
	Intent i = new Intent(this, MyMapView.class);
		
	List<Address> geocodeMatches = null;
		
	EditText addressText = 
                 (EditText) findViewById(R.id.editText1);
		
	String address = addressText.getText().toString();
		
	geocodeMatches = 
              new Geocoder(this).getFromLocationName(address, 1);
			
	if (!geocodeMatches.isEmpty())
	{
		i.putExtra("address", geocodeMatches.get(0));
		startActivity(i);
	}
}	

Updating the Map Location

At this point, the application is configured to accept a text address from the user, convert it to coordinates using geocoding and to launch the activity containing the map view. All that now remains is to add some code to the MyMapView class to extract the location from the intent and adjust the map view instance accordingly so that the map is centered at the designated location. Locate and edit the MyMapView.java file to implement the following code changes in the onCreate() method:

package com.example.mapexample;

import android.os.Bundle;
import com.amazon.geo.maps.MapActivity;
import com.amazon.geo.maps.MapController;
import com.amazon.geo.maps.MapView;
import android.location.Address;
import com.amazon.geo.maps.GeoPoint;

public class MyMapView extends MapActivity {

	private static MapController mMapController;
	private static MapView mMapView;
	
	public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_map_view_layout);
        
        mMapView = (MapView) findViewById(R.id.mapview);		
        mMapView.setBuiltInZoomControls(true);
        mMapController = mMapView.getController();

        Bundle extras = getIntent().getExtras();

        if (extras == null) {
		return;
        }
		
        Address address = (Address) extras.get("address");

        GeoPoint newLocation = 
           new GeoPoint((int)(address.getLatitude() * 1E6), 
                   (int)(address.getLongitude() *1E6));
		 
        mMapController.setCenter(newLocation);
        mMapController.setZoom(18);
   }
.
.
}

Breaking this down into sections, this code begins by obtaining a reference to the MapView instance in the user interface. This reference is then used to add the zoom controls to the map and to get a reference to the mapController object:

mMapView = (MapView) findViewById(R.id.mapview);		
mMapView.setBuiltInZoomControls(true);
mMapController = mMapView.getController();

Next, the code extracts the bundle of data that was passed to the activity as part of the intent, checks to make sure it is not null and then gets the object from the bundle that was assigned the key value “address”:

Bundle extras = getIntent().getExtras();

if (extras == null) {
	return;
}
		
Address address = (Address) extras.get("address");

The Address object passed in the intent contains the location to be displayed on the map. The longitude and latitude values are taken from this Address object and used to create a GeoPoint object. This, in turn, is used as the center point for the map, which is zoomed to a level of 18:

GeoPoint newLocation = 
           new GeoPoint((int)(address.getLatitude() * 1E6), 
                   (int)(address.getLongitude() *1E6));
		 
mMapController.setCenter(newLocation);
mMapController.setZoom(18);

Testing the Application

Compile and run the application, on either a physical Kindle Fire device, or using an emulator instance that has been registered with an Amazon account. Once the application is running, enter an address into the EditText field and select the “Find Location” button. The map should appear with the specified location set as the center point.

Summary

This chapter has worked through the creation of an example application intended to demonstrate the steps involved in using Geocoding to convert an address to longitude and latitude and the use of the MapView class to display a map centered at a specific location. Perhaps the most obvious omission from this example is a marker to designate the specified location on the map. In the next chapter, this will be addressed by adding an overlay to the map view.


<google>BUY_KINDLE_FIRE</google>



PreviousTable of ContentsNext
Working with the Amazon Maps API on the Kindle FireMarking Android Map Locations using Amazon Map Overlays