Saturday, August 29, 2009

The Joys of Android

Positive feedback:

Instead of continuing to bash the flotsam of obsolete programming languages like I did last week, today I'm going to describe a really nice experience I just had in the programming department instead; Developing an Andoid application.

Enter the Client:

The specification that my client had was clear; He wanted a demo/PoC of a smartphone application (iPhone or Android) that among other things first showed a Google map of an area with some markers on it, and when one of the markers was clicked, it would switch to augmented reality mode (AR) to display the markers in an overlay on top of what the camera in the phone dislay, so that people can orient towards points of interests in 3D using local landmarks.

And it was supposed to be done in under ten days. It sounded crazy hard to do, and at first I asked a couple of iPhone developers I knew if they could take it on, but they had their hands full, so I did some more research to see if I could do it myself.

Layar to the rescue:

It turned out that a very interesting Dutch company called Layar, which develops an Augmented Reality service by the same name. That's right, it's a service. That means that if you can get your user to download their (free) app from the Android appstore (iPhone support is coming soon, as a high priority), you can create your own headless REST service which pop up among available AR layers to choose from.

Here's a list of the currently created layers. If you get a quick idea of what you could use an AR layer for, it's probably already been implemented :) so check there first.

That means that 'all' I had to do was to create an android app that showed a map, and when clicked started the Layar app and pointed it to a special layer that I could create once I got my deveoper keys from Layar.

Luckily, I had just formed the Stockholm GTUG( Google Technology User Group), which among other things was eligible to receive review copies of books from O'reilly, Pragmatic Press and others, so I had several good Android books to browse through. Then I went out and bought myself a HTC Magic with extra toppings and flat rate internet.

SDK impression:

I used (naturally) Eclipse 3.4 with the spanking new 1.5v3 Android SDK which contained Google API support for maps and other things. It was very easy to get started, despite using Java. The APIs for various funcitons were mostly sane, meaning that they could be used without creating four extra levels of classes and the methods you really wanted to have for convenience sake were there, instead of missing so you had to write them yourself (classic Java).

My first try in developing the app used an internal webkit inside an Android app. I was really happy to find examples on how to do this in one of the books, since that meant that I could focus on effective development (in JavaScript) for a brwoser pretending to be a 'desktop' application.

I managed very quickly to embed a Google map in the 'internal' web page, and writing a shim that let me call Java methods from JS (and vice versa) was very straightforward.

The downside of this method was that (at least for the HTC Hero) it took over 15 seconds for the app to initialize. If tha map hadn't been the first screen, I could probably have used a background thread for webkit initialization, but I ended up ditching the browser method - despite its clear advantages.

Instead I found a View (A view is a kind of layout manager, which organizes other content for the Android app) called the MapView. I recommend following the 'official' example (which has a few typos in it), here. This view demanded a special application key from google code (You can get one here), which turns out to be a critical piece to do right. The problem is not obtaining the key, but to use the right public key from you SDK when applying for one.

Killer Keys:

There's a default keystore created for you when you install the Android SDK which has no password, and using the signature of that results in a developer key which only works inside a debug version of an app, so if you generated an .apk file and sign it using another keystore, the maps API key in your app will not work.

This is really simple and sound straightforward when I write it here, but when you're developing, it is very simple to forget to change codes and/or to forget which key signature to use when applying for one. This in itself would be very simple to spot if you get an error, which you don't.

What happens is that your markers show up at the correct place in the mapview, but the map is clean, consisting of just a thin grid of grey lines. The first times you see this, you immediately think that you have made a coding error, since the mapview do actually force you to create extra classes, implement extra methods and do the work that you really needed support for yourself - in a true, classical Java style.

So if you ever get those gray lines - I'd give you a 90% chance of having used the wrong keys somwhere. Just so you know, OK?

Once I got the mapview working, I needed to trap the screenpresses, so I could launch the Layar app. This is where Android started to shine. For every application in Android you can define different 'Intents' which are for all effective purposes 'Events'. So in an (ugh) external XML file, you define which intent string your app listens for and which class and method handles those intents.

Effective use of Events:

This means that each an devery app has an intent that starts it. This also means that it's possible to define intents that the app traps and handles before it has even been started (and which can start it on demand). I used this as a finishing touch, letting the app listen to incoming SMS, searching for a keyword. When it found the keywork it sent a message to the intent that started the main application. Worked like a charm :)

I also used this method when starting the Layar app. By browing through the log that I got from a shell that displayed ./adb logcat from my physical device (The HTC Hero) over USB, I saw the classname for the Layar App (com.sprx.layar), which I then used to create a new activity object, like this;

Intent intent = new Intent();
intent.setClassName("com.sprx.layar", "com.sprx.layar.Main");

And that's how an app start's other apps in Android. Pretty simple, isn't it?
Layar works like this;

1) You apply for a developer key here.
2) You login to Layar and create and name you first layer.
3) In the new and named layer, you point out a lot of things, but most important is the url that this new layer will get its POIs (Points Of Interests, for you non-mapping geeks ) from.
4) You implement the REST based service at the required url.
5) You download a special developer version of Layar, where you can enter you developer key and which will show all your dev layers in a specific tab inside the app.
6) Load your layer. Scream, curse, despair, check logs, read up on coordinates. Check in Google Earth. repeat.
7) Success!

REST assured:

Item number (4) here sounds ominous, but it really isn't. I naturally implemented the service in Googel App Engine vanilla python. It took all of two hours to register, create, upload and get something visible, and part of that time was dinner. There was two reasons that this went fast; a) I was only doing a demo, so all POIs I returned was hardwired into the source code, b) you really only need to implemenet GET, since Layar only ever (for now :-P ) reads info from your backend.

I had a lot of small troubles converting coordinates and making them show correctly in my layer, and almsot all of them was due to rounding errors or plain stupidity on my part. When I started checking all coordinates I sent back in Google Earth (where you can just enter degree coordinates into the search field) and I found myself north of Scotland or in Dubai, I had an easier time finding my bugs.

I managed to deliver the PoC app on record time, fixing design erros quickly due to the web-based nature of both App Engine and the Layaer adminstrative interface. I'm actually a bit on an Augmented Reality tear at the moment and will present and demo the app on out first GTUG meeting next Thursday. Now for some more coding :)



Zoom said...

Nice going!

Peter Svensson said...

@Zoom. Thx! I was lucky. Lucky enough to have had spent lots of time on similar stuff before :)

Zoom said...

Luck or skills, who knows the difference :-)

Rishikesh said...

Hi, I am trying to develop an augmented reality app like wikitude drive.. can u help me wid some tutorials??

Peter Svensson said...

Hi @Rishikesh, unfortunately I don't do any AR stuff any more (or currently at least), so the best I can do is to refere you to Layaers own dev pages;