Developer Central
Developer Central Links
Android Sample
Envirofacts MultiSystem Representational State Transfer (REST) Application Programming Interface (API)
- Overview
- Create a New Project
- Run the Application
- Locate More Information on Envirofacts MultiSystem Data
Overview
This
sample will provide the steps to create a simple Android application that can
consume Envirofacts Multisystem Data. The Envirofacts Multisystem data is comprised of multiple environmental databases for facility information, including toxic chemical releases,
water discharge permit compliance, hazardous waste handling processes, Superfund status, and air emission estimates. The API Data Sample code below will query and display facility information from this database.
Following these steps in order will allow the application to
recreate the sample project. Download the code sample project in order to get the Eclipse Project files that were created by following the steps.
This solution was built using:
- Eclipse Indigo Service Release 1 (3.7.1)
- Android Accessory Download Kit (ADK) for Android platform 2.3.3
Assumptions:
- Eclipse
is already set up with the Android Software Development Kit (SDK).Please go here for more information on setting up the Android Developer
Tools (ADT) plug-in http://developer.android.com/sdk/eclipse-adt.html.

- The
developer has already registered with Google to use the Google maps API. Please
go here for more information on setting up the Google Maps API for android https://developers.google.com/maps/documentation/android/.

For this sample, create a Google Map based on the device's current Global Positioning System (GPS) location. This map will then display companies provided by the Envirofacts MultiSystem Web service, 10 at a time.
Create a new Android Project in Eclipse.

Name the project. For this example it is named SampleEpa2.

Click "Next" and the select the build target (Google APIs 2.3.3).

Click "Next" to finalize the Android Project configuration.

Now that the project has been created additional configurations need to be added to include the Google API and the application permissions. This can be done by replacing the contents of AndroidManafest.xml as follows.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="gov.epa.envirofacts"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<uses-library android:name="com.google.android.maps" />
<activity
android:label="@string/app_name"
android:name=".SampleEpaActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</manifest>
In order
to use the Google Maps API, the MapView has to be included in main.xml under the
res\layout folder. The MapView requires
that an API key is provided. The one included in the below snippet will
not work. As stated in the
assumptions section of this document, one can be obtained by following the steps
outlined in the following link: http://code.google.com/android/add-ons/google-apis/maps-overview.html.
The below Extensible Markup Language (XML) includes the RelativeLayout
which allows the MapView to move and resize as needed.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mainlayout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.google.android.maps.MapView
android:id="@+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
<!-- "Replace appKey this one is invalid" -->
android:apiKey="0gxruET-nFtQGBAD_y718iddbkdAdAqq6Yp6uMh"
/>
</RelativeLayout>
Now that the project has been set up and the Google API has been included, some files need to be included from this sample project (two image files with which to mark the Google map).

Two files for parsing the XML from the EPA Web service call.

The XML parser puts the output of the Web service into a List of DFEObjects which is a Data Transformation Object (DTO or Bean) so that it can be utilized within the projects. To create the DFEObject create a new class with the following inputs.

Click "Finish" and then open the created file. Replace the contents of the created file with the below java code.
package gov.epa.envirofacts;
import com.google.android.maps.GeoPoint;
public class DFEObject {
private double latitude = 0;
private double longitude = 0;
private String name="";
private String address="";
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public GeoPoint getGeoPoint(){
return new GeoPoint((int)(latitude*1E6), (int)(longitude*1E6));
}
The Google MapView works with overlays to place markers on maps. To create an overlay in this project, create a new class that extends Google's ItemizedOverlay class.

Replace the contents with the below code so that that the markers that are created can be displayed and clicked on to show more details.
import java.util.ArrayList;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.MotionEvent;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
public class EpaItemizedOverlay extends ItemizedOverlay {
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
private Context mContext;
public EpaItemizedOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
}
public EpaItemizedOverlay(Drawable defaultMarker, Context context) {
super(boundCenterBottom(defaultMarker));
mContext = context;
}
@Override
protected OverlayItem createItem(int i) {
return mOverlays.get(i);
}
@Override
public int size() {
return mOverlays.size();
}
public void addOverlay(OverlayItem overlay) {
mOverlays.add(overlay);
populate();
}
@Override
protected boolean onTap(int index) {
OverlayItem item = mOverlays.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.show();
return true;
}
}
In order to display a menu that will allow the user to navigate to the next 10 items on the map, add the following code to bottom of the sampleEpa2Acitivity class.
protected boolean isRouteDisplayed() {
return false;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int actionType = ev.getAction();
//System.out.println("Action Event="+actionType);
switch (actionType) {
case MotionEvent.ACTION_UP:
buildOverlay();
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
boolean supRetVal = super.onCreateOptionsMenu(menu);
menu.add(Menu.NONE, 0, Menu.NONE, "Last 10");
menu.add(Menu.NONE, 1, Menu.NONE, "Next 10");
return supRetVal;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 0:
if(currentPage<1){
currentPage=1;
}
currentPage=currentPage-1;
buildOverlay(currentPage);
return true;
case 1:
currentPage=currentPage+1;
buildOverlay(currentPage);
return true;
}
return false;
}
All Android applications start with an activity. When the project was set up, the activity class SampleEpa2Activity was created automatically. In order to get the map and markers to display, this class needs to be modified to pull all of the previous code changes together. Within the SampleEpa2Acitivity class declaration include the following Attributes:
private MapView mapView;
private LocationManager locationManager;
private int currentPage =0;
To update the MapView with the current location of the device that this application is running on, a LocationListener needs to be created. This can be an inner class within the SampleEpa2Activity class. Add the following lines of code before the last bracket in the SampleEpa2Activity class.
@Override
public void onLocationChanged(Location location) {
int lat = (int) (location.getLatitude() * 1E6);
int lng = (int) (location.getLongitude() * 1E6);
GeoPoint point = new GeoPoint(lat, lng);
mapController.animateTo(point); // mapController.setCenter(point);
mapController.setCenter(point);
System.out.println("Location Change");
buildOverlay();
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
In order to make a service call to the EPA Envirofacts MultiSystem RESTFUL Service, include the following method declaration in the SampleEpa2Activity class. The service call expects the minimum latitude, minimum longitude, maximum latitude, minimum longitude, starting record, and maximum record. More details on what can be passed to the service can be found at Envirofacts Data Service API.
public String executeQuery(double minLat, double minLon, double maxLat, double maxLon, int page, int pageMulti ) throws IOException, URISyntaxException{
URL url = new URL("http://iaspub.epa.gov/enviro/efservice/multisystem/minLatitude/"+minLat
+"/maxLatitude/"+maxLat+"/minLongitude/"+minLon+"/maxLongitude/"+maxLon
+"/rows/"+((page*pageMulti)+1)+":"+((page+1)*pageMulti));
System.out.println(url.toString());
System.out.println(url.toExternalForm());
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String inputLine;
String totalString = "";
while ((inputLine = in.readLine()) != null) {
totalString = totalString.concat(inputLine);
}
in.close();
return totalString;
}
The service call returns a list of companies within the coordinate range provided. These companies have coordinates, names, and descriptions. This data is all returned in an XML-formatted string. Below are the methods that execute the method above, parse the XML string, then add the markers to the Google MapView overlay. This should be added the SampleEpa2Activity class.
GeoPoint minpoints, GeoPoint maxpoints, int page) {
try {
//Flip min point latitude with max point latitude
String results =executeQuery((double)maxpoints.getLatitudeE6()/1E6,
(double)minpoints.getLongitudeE6()/1E6,
(double)minpoints.getLatitudeE6()/1E6,
(double)maxpoints.getLongitudeE6()/1E6,page,10);
if(results!=null&& results.length()>0){
List<DFEObject> dfePoints = getListOfPointObjects(results);
for (DFEObject dfeObject : dfePoints) {
itemizedoverlay.addOverlay(new OverlayItem(dfeObject.getGeoPoint(),
dfeObject.getName(),
dfeObject.getAddress()));
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
private List<DFEObject> getListOfPointObjects(String results) {
XmlParser parser = new XmlParser();
List <DFEObject> dfeList = null;
try {
parser.initializeReader();
dfeList = parser.parseDFEObjectResponse(results);
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return dfeList;
}
The above methods have been encapsulated into a buildOverlay method so that it can be called by other event triggers. This should be added the SampleEpa2Activity class:
buildOverlay(0);
}
protected void buildOverlay(int page){
mapView = (MapView) findViewById(R.id.mapview);
Projection projection;
projection = mapView.getProjection();
GeoPoint minpoints = projection.fromPixels(1, 1);
GeoPoint maxpoints = projection.fromPixels(mapView.getRight(), mapView.getBottom());
List<Overlay> mapOverlays = mapView.getOverlays();
mapOverlays.clear();
Drawable drawable = this.getResources().getDrawable(R.drawable.marker);
EpaItemizedOverlay itemizedoverlay = new EpaItemizedOverlay(drawable,mapView.getContext());
getMapPoints(itemizedoverlay,minpoints,maxpoints,page);
if(itemizedoverlay.size()>0){
mapOverlays.add(itemizedoverlay);
}
mapView.invalidate();
}
Finally, the onCreate method needs to be changed from the default one created when the project was created to the following:
super.onCreate(bundle);
setContentView(R.layout.main); // bind the layout to the activity
// create a map view
RelativeLayout linearLayout = (RelativeLayout) findViewById(R.id.mainlayout);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapController = mapView.getController();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
0, new GeoUpdateHandler());
mapController.setZoom(14); // Zoom 1 is world view
buildOverlay();
}
Run the application and view a map based on the current location with markers on it that are clickable.
If the menu button is clicked, the last/next 10 companies can be displayed.
Locate More Information on Envirofacts MultiSystem Data
Each dataset has a dataset location path that gives the URL that will be needed to reach the data. The sample code can be adjusted to get that data and display it as well. For more information on the RESTFUL Web services provided by the EPA go to Envirofacts Data Service API.


