Edit 11/08/2010 - I was inaccurate when I stated that the NRCS WAI has only a SOAP/RPC access - it has GET and POST as well. I'm currently revising my Android app to parse the WAI XML.

First things first: it’s aboot time.  I’ve spent enough time dinking around with Android that this post should’ve occurred a long time ago.  So, here it is, enjoy.

Recently, I developed an Android application to access the USDA NRCS’s public Where Am I? (WAI) service.  The WAI service provides land-related information from a geospatial location within the United States.  This took about the equivalent of a weekend (16 hours or so), but it was spread out over about a week, so I'm still calling this an "App a Weekend" entry. Deal with it. There are a few gotchas and points along the way that are worth noting as I developed this application.

The Where Am I? service provides information for a geospatial point on the map: Congressional District Code, ID, Name, Congressperson’s name, Hydrologic Unit Code, Major Land Resource Area, City, State, Zip, and Tribal Land ID/Name, among other information.  The service drills through multiple layers of geospatial data and gives back an attribute list.  Useful for some purposes when doing land-based assessment as a lot of NRCS applications may do, what with them being the Natural Resources Conservation Service.

The idea for the WAI Android application came from my work inventorying potentially enterprise-ready existing shareable services at the NRCS, which ones are being shared, and which ones were intended to be shared.  Additionally, some discussions with developers at the USDA about mobile access to NRCS data services needed some level of pragmatic understanding.  Why not write an Android app and exercise the API just enough to make a semi-useful app and exercise the end-to-end Android dev process?

Semi-Useful Design

My intended design was to have an Android application that not only displayed a map from which the visible latitude and longitude could be obtained but also use the geolocation services of the Android device (GPS, network) to obtain the latitude and longitude.  The geospatial coordinates could then be passed to WAI and the WAI attribute results would be displayed.  Pretty straighforward.

The Where Am I? Service

The WAI service is written in .NET and exposed as ASMX which provides a WSDL as an API.  A few issues with this right off the bat.  Android has no native SOAP client to dynamically create a proxy.  There is, of course the Apache Axis library, but those are huge, ~8mb, and the proxy client built by Axis is also pretty large.  Size is an issue in any mobile app and including libraries not specifcally optimized for the platform's not recommended. There’s an Android implementation of ksoap2, but there were lots of comments of its usability and feasability, so I passed on that one.  Additionally, XML parsing is reputed to be quite expensive in Android.  Another issue is that the WAI service is hosted behind a port redirector and therefore WSDL for the service indicates its endpoint at port 42500, which is incorrect.  This issue causes dynamically generated SOAP proxies to fail.  The work around is to manually generate the proxy (using wsdl.exe in .NET for example) and then manually correcting the port.  SOAP access to WAI seems less and less likely.

For a mobile device, it really seems like a REST/document style interface with json would be better than an RPC style interface, given the potential size of a proxy client and supporting libraries. Why not write one?

The REST Service for WAI

I wrote a very quick REST service using ASP.NET MVC2 and pushed this app to Azure, http://wai.cloudapp.net

It has a very basic human user interface and some documentation on the single existing REST method.  Currently, there's one method on the controller that takes lat and lon value, calls the USDA NRCS SOAP webservice via a manual proxy class, and returns a full set of data attributes as a JsonResult object.

Creating an Azure app from an existing MVC2 app was cake - add a Windows Azure Cloud Service project to the existing solution. Publishing to Azure was surprizingly easy, with one hitch: our worktops are XPSP3 and the latest Azure SDK for VisualStudio 2010 will only work on Vista/7.  I published to the cloud using my personal laptop (Windows 7).

It might’ve been slicker to use Google App Engine to host the REST proxy, but the nerd humor of a GOOG app calling MSFT service can't be beat.

Finally, the Android App

With the REST service in place, utilizing in an Android app was a snap.  Obtaining a GPS/Network location from the device is well explained in the online SDK.  Writing a REST client in Java within a thread is as you’d expect (although this is not the recommended pattern, see this very informative talk from I/O on Developing REST Client Applications; a talk I opted not to attend and am grateful they posted the talk and pdf slides online).

I made a main Activity class that contains the Maps MapView, one for the Aboot and WAI Results dialog boxes, and another for the Preferences (an upcoming enhancement). Two straight Java classes, a REST client to house static methods around issuing an HttpClient GET call, and an interface class for my RestRequestCallback that my main Activity implemented in order to get the info back from the threat that starts the REST call.

I obtained a Google Maps API key in order to utilize the Google Maps API, which is separate from the default Android API.  It’s used in order to enable the tile service of the Maps API to function.  Also, I had a development (“debug”) key per machine I was developing on (I used both my desktop and laptop to develop the app).  This meant i had to keep changing the hash string that enabled the Maps API in the view layout, which wasn’t hard, just slightly inconvenient.

Testing on the emulator's really easy and I'm always impressed with the SDK's qemu running Android. Once started, it's snappy and responsive. The emulator has no GPS, so you've got to push a lat, lon to it via the DDMS emulator interface ui or via telnetting to the emulator and issuing a "geo fix lon, lat" command to simulate a location fix. Incidentally, there's a Galaxy Tab add-on for the SDK so you can skin the emulator to look like the upcoming 7" device, if you're so inclined.

Signing an application is actually really easy from within Eclipse -  it’s a menu item added to the right-click context menu by the Android SDK plug-in.  It’s not really that hard via the command line, either.

Publishing to the Android Market was also an interesting experience.  You upload the apk (compiled Android app) and a few screenshots (optional).  Once you do, there’s an entry in the developer listing.  And it can’t be removed.  Even if you unpublish your app, the app remains in your list (not on the Market, but in your developer dashboard for the Market).  I initially compiled my app in a very generic namespace, net.bespokesystems, and then wanted to change it to net.bespokesystems.demo.RestLocation, a much better namespace.  Seems like the namespace is the key for the developer dashboard, so no changing that - got to publish a new app.  And wouldn’t you know, can’t remove the app from my dashboard.  So, although unpublished, there’s an app entry that’s there.  At the time, there were no users of the app (I’d installed the apk manually on my Nexus One), but after a few days, oddly, there were!  It seems like there must be people who automate installation of apps as they’re published, maybe some feed that I’m unaware of plus a delay in reporting of installations.  I’d literally had the poorly-namespaced app published in the Market for less than 20 min.  I’ll have to follow up on either on the dev mailing lists or irc channel to determine some of the Market's logistics. One thing I didn't have to do was wait (I'm looking at you Apple App Store).

Using the Google Chart API for QR codes, I created the clever little QR image above that, when scanned with the Barcode Scanner app on your Android phone, directs you to the download for the app on the Market.

There are some interesting bits in the Android app lifecycle - rotating the screen pauses and restarts the app - and as a developer one has to accomodate for saving state.  I got a bit into the Preferences API, alternate layouts and screen depths, and making a simple icon.

I hope to place both the Android app and the Azure MVC app in a public repository soon for anyone who wants to see some awesome slapdash code.

A few ideas on future updates:

... for the Android app

  • Use a better pattern for accessing REST services
  • Allow the user to change the map type, from satellite to road
  • Reduce REST query timeout to accomodate for NRCS WAI service response timeouts
  • General polish (release notes, proper liste provider for WAI results)
  • Better control over GPS/Network/Wifi location behavior

... for the WAI REST service include

  • REST methods to allow the request to specify which WAI attributes to return
  • Google map for the UI piece
  • Reduce timeout to NRCS WAI service and add a single retry to accomodate for the NRCS WAI service’s timeout issues