Days 7 – 9: Trial and Error

So, 2 days without an update. That’s not to say I haven’t been working on it, but I’ve been mostly just trying out various different methods of displaying the overlays on the camera view.

Today’s Results

Last time I posted, I had the locations overlaid, but only moving from the left of the screen to the right. After day 7 I had it moving both left and right and up and down. I spent most of day 8 trying to get them to move slightly differently, but in the end decided that what I had in the first place was probably the best I would get. Today I played with the distance values, and now have the pointers resized and moving at varying speeds depending on how close you are.

Again it’s hard to show it working properly without any locations visible, but the example here is showing various cinemas in a 10km area. The large one is my town’s cinema, the smallest ones are in other towns further away.

Then, if I rotate the phone to the right a bit:

The nearby one has moved much further to the right than the distant ones. This is similar to the perspective of objects that you can see. For example, right now, I’m sitting in front of my computer, which is in front of a window. If I move to the left, I can’t see the monitor in front of me any more, but I can still see the next house out of the window.

The slider doesn’t do a lot at the moment. It’s supposed to affect the display area, but at the moment it only uses these values for the google search. While this does prioritise nearby locations, if there aren’t many locations that match in that area, it’ll still return some faraway things. I think rather than making this a fully adjustable scale, I’ll probably make 3-4 ‘levels’ of search area. Right now the perspective/sizes change over quite a large distance, with the smallest size being at over 10km away. Obviously if you’re in a city and actually looking at buildings, you don’t care about things 10km away, and all of the things you’re looking at would be within 100m of you. Right now, those would all be shown at the same size. I’ve had to do this for testing because there aren’t any locations near me which I can search. I’m also not applying any specific calculations to work out the size. I’m using log on the distances and going from there, but then I’m just using a bunch of if statements to categorise each point into a specific size.

If I can work out a better way of calculating it I might make a full sliding scale. I also need to find a better way to filter the search results though, as right now it would still display faraway items if you set the area to the minimum, and these results were producing huge/inverse images because it was scaling them by a negative number from the calculations I tried. There are various ways around this, but for now the method I’ve got is working well.Currently I’m aiming to have, say a”city” view, where you just want things that you can see very close by, a “wide range” view, where you can see all of the results in the region, and 1 or 2 in between that. That should be sufficient for now.

The Code/Maths

I won’t go into all the details because it hurts my head now, but I’ll explain a few of the basics.

I said a few days ago that I didn’t think I’d have to worry about the Accelerometer values, but it turns out that I do. The orientation values basically show how far they are rotated away from a specific point, but not in positives and negatives. For example, if you’re holding it flat, it will say 0 degrees. You rotate it upwards slighly, it will say 10 degrees. But if you rotate it downwards slightly from flat, it will also show 10 degrees. The values also jump between 0, 180, and -180 at certain points, so it can be quite confusing. Enter the accelerometer. This sensor -does- know if it’s tilted upwards or downwards. The specific numbers it’s giving don’t mean much, but the key piece of information here is whether it’s positive or negative. As with the previous example, you have 10 degrees in both cases, but in one case the accelerometer value will be negative, and in the other, it will be positive. You can use this in a simple if statement to perform a different calculation depending on the accelerometer value.

After implementing the movement in two dimensions, I ran into another problem. It worked fine if I was holding it perfectly horizontal, but if it was rotated sideways, moving it up or down would result in the points jumping across the screen at certain points. The solution to this was using the third orientation value, and another accelerometer value. So basically, I have 4 sets of calculations for each combination of positive or negative on each of the accelerometer values. This then allows me to rotate the points to match the users view too, and overcomes the jumps across the screen.

As I’ve said, I’m not going to go into detail here, but I’ll give 3 suggestions:

Read this tutorial. I don’t think the maths is entirely correct, but it should give you an idea of how it works:

http://www.devx.com/wireless/Article/42482/1954

Download “SensorList” on your Android phone. This gives you the outputs for each of the sensors, and a graph of them. From this, you should be able to work out what you need to do with the numbers. Pay close attention to what happens to the numbers as you tilt it past horizontal or vertical on each axis.

Contact me via comments or email and I’ll try and explain it a bit better. I also plan on writing an in-depth tutorial once this is all finished.

The distance calculations again took some trial and error. Many attempts resulted in markers which were either far too big, far too small, or not enough differentiation between the distances. I overcame this by first finding the logarithm of the distances. Currently, I do want to see faraway points, but I don’t care about much beyond 10km away. In log base 10, 10000 is 4. Using a sort of semilogarithmic scale, I took these values, and as the log10 of the distance went up by 0.25, I increased the scale by 0.2, ranging from 2 to 4, which is between 100m and 10km. There are no results closer than 100m to me right now, and only a few within 500m or so, so this worked well for now. But when you’re in a city and just want to see what’s within 100m of you, this will have to be changed. The log10 of anything below 1 is a negative number, which would cause issues with the scale, but this isn’t a problem in this case because the GPS isn’t accurate enough to say that something is less than a meter away from you. But I’ll have to change the scale of this for using a smaller search area, such as between 1 (10 meters) and 2 (100 meters), possibly up to 3 (1km) for very small outliers.

Another issue I encountered was that the app was getting increasingly slow, to the point that it was very difficult to even type in search queries, and the points were not moving across the screen very smoothly. This was solved (partially) by looking into the garbage collector. If you look at LogCat in DDMS when you have an app running, you’ll see something along the lines of “GC cleared 1000 objects in 100ms”. What this means is that it’s periodically stopping for a short period to clear stuff out of the temporary memory. 100ms doesn’t seem like a lot, but it makes quite a difference with a real time application of this nature. Especially when it has to do this for every draw cycle. The reason that this happens is when you create objects in some way like Paint paint = new Paint(); it’s creating a whole new object which you’re not getting rid of. Java deals with this stuff on it’s own quite well, compared to languages like C where you have to do all of this yourself.

In my case, I was creating new Location objects for every search result (up to 8 at a time) on every draw cycle (which occur multiple times per second). The solution to this is to declare your objects as private at the start of the program, and set them up in your onCreate method. You can then simply edit and refer to them in your draw cycles, rather than creating endless objects multiple times per second. Mostly these sorts of problems can be solved by looking for any lines that are creating objects by using the new operator, particularly within your onDraw methods, and also sensor listener methods. The background APIs are going to do a fair bit of object creation on their own too, so you won’t be able to get rid of everything, but you’ll be able to avoid significant issues. There’s also the issue that declaring the object for the entire program will take up more memory in the long run, rather than only for a short time. Depending on the nature of your app you might not want to do something like this, but for graphics-heavy apps, it helps a lot.

The Next Steps

I have the foundations augmented reality working now. There are a few more steps to perfect it, though I’d like to move on to the bigger parts and come back to the minor details when there’s time.

  • Showing details of the location on camera view. Currently there’s no way to see -what- locations you’re looking at, unlike on the map where you can click to see the name of it. I had trouble implementing any sort of click listener for the images, but there’s probably a way. Alternatively, an overlay could just display the details of the nearest point to the center.
  • Set up the different search areas to work correctly.
  • Sort the Google search results so that irrelevant results are discarded, and closest items are prioritised. Also need to search through multiple results beyond 8.
  • Test to make sure the results are accurate in a city area.

That’s about it for the app itself. Beyond that, I need to create a database for adding my own points, so that it can be demonstrated at the University, and extended further in the future. This is fairly simple, and I’ll probably just do it by setting up a MySQL server on my website and a PHP script to create the JSON output. It would be easier to encode the JSON output in Java using the Jackson libraries, but then it’ll take more work to it up to receive HTTP requests. Javascript is another option but I’m not familar with it.

Tomorrow’s Goal

One more day working on the minor points described above. Location details are very important and I still need to decide on how to display it. Search areas are quite important but I’m pretty confident of how to do this. Google results are less important as I won’t need to be showing many Google results in my University demonstration, but it would be good to improve this.

Links

As I said, most of this was all trial and error til I got it right. I’ll point you to this tutorial again which helps with getting started in Augmented Reality, though the maths doesn’t appear to be entirely correct.

http://www.devx.com/wireless/Article/42482/1954

This page explains how to make your app more efficient by dealing with the Garbage Collector.

http://blog.javia.org/android-allocation-free-code-avoids-the-gc-freeze/

This app is very useful for working out what you need to do with your sensor outputs. It gives you every number your sensors are outputting, and plots them on a graph.

http://www.androlib.com/android.application.com-miian-android-sensors-xmiE.aspx

Alternatively, here’s the QR code link which you can scan on your Android phone, to take you directly to the market download.

http://www.devx.com/wireless/Article/42482/195

Day 6: Camera Location Search and Custom Views

Just a short post because it’s late. Today was a bit frustrating, mostly trying to do minor things, but the result feels like a fairly big breakthrough, and the app is now doing what it was originally intended to do, albeit in a very rough form.

Today’s Results

The main result today was that I can now search for locations and display them on the camera view. It’s really starting to come together now.

The only thing that remains for this part of the app is to do a bit more with these overlays so that they’ll line up correctly with buildings at different angles and distances. This is mostly just maths that is going to take some thinking about, but the basis of the application is mostly there now.

A few pictures for now:

The first 2 are searching for the local Tesco’s, before I added search boxes there. Not particularly descriptive pictures considering I can’t actually see those locations from here. But, you can see that there are -some buildings- over there in the distance. And just for proof, here’s some map view shots to confirm.

So you can see I am indeed facing Tesco, and you can just about tell that I’m standing in that place from the map -  you can see the power line going through the garden.

A lot of the day was spent screwing around with XML and views trying to get the search box on the camera view, and changing them to image buttons. I got it in the end though.

I’m pretty excited at the progress I’ve made, and how close it feels to the end now. I just need to do some maths-foo, and then this section is done. After that I plan on making my own server application for adding locations too, but that shouldn’t be too complex. Then I just need to make it so that it can be sent search queries, and output the result in the same JSON format that I’m already dealing with for Google.

I’ll post some code bits tomorrow, though there’s not too much to see beside the calculations for displaying the markers on the screen.

Tomorrow’s goal

I’ll be going in to town to test it out some. I’d like to try and implement some of the maths to calculate the height, and varying positions depending on the distance, but I think that’s mostly going to be down to trial and error.

Links of the Day

Only one really. Most of the day was just testing stuff, and combating the NullPointerExceptions that they resulted in

http://mylifewithandroid.blogspot.com/2008/04/custom-views.html
Fairly simple explanation of how to make your own custom views and put them into the XML file.

Day 5: CameraView and some Math

As expected, today turned out to be a bunch of experimenting and not a lot of results. I have a general grasp of what I need to do now, but it looks like it may involve a bit of maths.

Also, I’ve noticed that my blog is starting to pop up on Google search results for the sort of things I was searching for myself a few days ago. The code snippets I post here are probably a bit useless when they’re not seen in context with everything else, but then at this point I’m mostly posting them for myself to look back on later on. I plan on writing some tutorials once this is all finished, because there aren’t many out there, but for now, if you happen to come across this and you need some help trying to do similar things to what I’m doing, drop me an email at android@lc8n.co.uk

Today’s Results

Not a lot to show today, but I guess I do have something that could be classed, very very loosely, as an augmented reality application. I’ve moved onto another screen now, the Camera view. The intent is to take those Google search results I had on the maps yesterday, and have them being overlaid in the right place on the map.

I spent a long time playing around with overlay stuff, and trying to understand some maths, but in the end I tested it out, and I now have an overlay that shows you the location of the nearest compass point. That line probably doesn’t make much sense, so here’s some pictures :

(10 minutes later, after first posting the pictures I realised I’d done it wrong! Fixed now)

It also works correctly in Landscape mode now:

Also just to show that it is correct, here’s a comparison in the map view. I am indeed sitting in that location, facing west.

Yes, I do need to fix those buttons.

The Code

Of course, this is just dealing with changes in one dimension. When it comes to labelling buildings, I’m going to need to worry about 2 or 3 dimensions. The labels should move up or down depending on which way you’re pointing the camera, and it also needs to take into account the distance away it is, to get the perspective right. So that close things will move off of the screen if you move it a small distance, and far things stay on the screen across a larger range of movement. For example, on the middle screenshot above, if the ‘West’ label was actually labelling my monitor, I wouldn’t want it on the left screenshot, because it’s off the screen. In the case of compass distance, we’re labelling something infinitely far away though.

The code for working this out is pretty basic at the moment. I read some things about more complex calculations of the direction, but they didn’t seem to work, and right now, I’m able to do what I need to do through simpler means. As long as it works when I’m either holding it upright in portrait and landscape modes, that’s fine. Even just one of those would be ok for now, but it seems to be ok with both. I don’t need to worry about making it work when I’m upside down or laying on the floor. I also saw mention of using the accelerometer, but as of yet I don’t need to. Anyway, here’s an idea of the code for this bit -

if(dir<45)
{
position = (canvas.getWidth()/2) – 50 – (dir *(canvas.getWidth()/90));
canvas.drawText(“NORTH”, position, canvas.getHeight()/2, paint);
}
else if(dir>45&&dir<135)
{
dir = dir-45;
position = canvas.getWidth() – 50 – (dir *(canvas.getWidth()/90));
canvas.drawText(“EAST”, position, canvas.getHeight()/2, paint);
}
else if(dir>135&&dir<225)
{
dir = dir-135;
position = canvas.getWidth() – 50 – (dir *(canvas.getWidth()/90));
canvas.drawText(“SOUTH”, position, canvas.getHeight()/2, paint);
}
else if(dir>225&&dir<315)
{
dir = dir-225;
position = canvas.getWidth() – 50 – (dir *(canvas.getWidth()/90));
canvas.drawText(“WEST”, position, canvas.getHeight()/2, paint);
}
else
{
dir = dir-315;
position = canvas.getWidth() – 50 – (dir *(canvas.getWidth()/90));
canvas.drawText(“NORTH”, position, canvas.getHeight()/2, paint);
}

Looks a bit long winded, but it’s pretty simple. Basically, it’s printing a different string depending on which quarter of the degree range you’re facing. it’s split into 5 because north is from 0-45 degrees and 315 to 0 degrees. In each case, it converts the degrees into a relative position between the two nearest compass points, and then converts that into a position on the screen. Wow, that didn’t make much sense. I’m sure I could do it in a much simpler way, but this was just a basic test for the moment.

I also had a look into the Google search results from yesterday in a bit more detail. There were two issues that came about yesterday. For one, it was showing things that weren’t at all relevant sometimes (pubs when I searched for train stations), and sometimes it wasn’t showing the most relevant things either.

The first issue is fairly easy to filter out. There’s also an ‘accuracy’ value for each search result. The actual train stations had an accuracy of 1, while the pub had an accuracy of 8. So, obviously the lower accuracy value the better. Turns out that the pub actually does have a review that mentions that it’s easy to get to from the train station, which is why it showed up, but fortunately Google has taken care of this issue by calculating this accuracy score.

I also realised that it was only returning 4 search results. To see more you need to specify a “start” value. I’d like to be able to do this without having to send countless search requests, but I’m not sure how easy that would be. Ideally I’d like to be able to sort them by accuracy, and return the top x number of results, or everything with an accuracy below a certain number. Unfortunately Google doesn’t seem to provide the functionality to sort local search results in any other way. You can choose to sort news and blog posts by relevance or date, but it would be nice to see the option to sort local results either by distance or relevance. I guess that could throw up some other issues too though.

Another handy feature is that you can provide it with an area to search. Previously I was just giving it a center point, so it was giving things that were quite a way away sometimes. But again, thanks to the magic of google’s API, you can get the degrees that are covered by your current view, so you can provide these to the search easily. That way, you’re only getting search results that you can actually see right now. In the context of the camera view, you’d probably want to limit it to locations that are pretty close to you, and this could maybe be controllable by the user to say how far away they want to show. I’ll need to work out how to get these sort of numbers into the correct format.

double lat = p.getLatitudeE6()/1E6;
double lng = p.getLongitudeE6()/1E6;
double latspan = mapView.getLatitudeSpan()/1E6;
double lngspan = mapView.getLongitudeSpan()/1E6;
results = gs.runJSONParser(URLEncoder.encode(edit.getText().toString()),lat,lng,latspan,lngspan);

And the code in the search class to run the search -

Reader r = new InputStreamReader(getJSONData(“http://ajax.googleapis.com/ajax/services/search/local?v=1.0&q=”+request+”&sll=”+lat+”,”+lng+”&sspn=”+latspan+”,”+lngspan”&rsz=large”));

So, first we’re giving it our search query, then our location. After that, the sspn parameter gives our search area. The rsz parameter of large specifies that we want 8 results. Unfortunately you can only choose between 4 (small) or 8 (large) here. You can then supply &start=9 after that, and so on, to get more results. There is also a field in the JSON response that shows how many results there are, so you know how far to look.

Tomorrow’s Goal

Hopefully make some progress on overlaying the locations on the screen. I doubt I can get it perfect tomorrow, but hopefully something that generally works. I won’t be able to test this too well tomorrow at home, but I’m going into town on Sunday, so I’ll be able to see if it’s working then.

Links of the Day

http://www.devx.com/wireless/Article/42482/1954
This article basically gives you a crash course in starting up an AR application. A lot of it covers the same stuff as my previous posts, but it’s mostly concise and simple. It only covers the backend stuff though, rather than any output.

http://www.devx.com/wireless/Article/43005/
The second part of the above article. As I said, the maths here doesn’t seem to work for me, but so far I haven’t needed it. That may change tomorrow.

http://code.google.com/apis/ajaxsearch/documentation/reference.html#_intro_fonje
A detailed list of the parameters you can provide in each sort of Google search

http://www.mail-archive.com/android-developers@googlegroups.com/msg22032.html
A pretty simple example of showing Overlays on the camera view. Probably irrelevant for most people, unless like me, you jumped into making an AR app without any experience of Android development!

If you have any questions or comments about anything here, feel free to contact me, either via the comments on here, or email at android@lc8n.co.uk

Day 4: JSON and Google Local Search

I posted yesterday that it looked like getting location information from Google would be pretty complicated. It took a while to work out what I needed to do, but in the end it wasn’t too bad.

Today’s Results

I met my goal again for today – I can search for specific locations, and they’re labelled on the map.

The items on the far left and right are indeed the nearest train stations. The one in the middle is actually a local pub – I’m not really sure why this result came up. For the most part this works really well though. It’s a bit laggy on loading the results, I need to come up with some sort of “Please wait, loading” popup, because currently it just hangs for a few seconds. In some cases it freezes when I search, and I’m not sure why, it seems fairly random. But generally, it works. If you tap one of the markers, currently it gives you a popup with information about the location

Compared again to Google maps to show accuracy -

Obviously I could do with making my markers smaller, and ideally tapping on a location would bring up another overlay, or take you to another screen. It’s just for testing purposes right now though.

The Code

Strangely, Google saw fit to not include any Google search functionality in their API. Presumably this is so people can’t steal their results and use them without branding, or something to that effect. I don’t really see how this is any different to being able to access it through your own web site though. But, there’s still a way to do it. I thought this would involve coding my own search script in javascript or some such, but it turns out they’ve done that much for us.

If you take this link – http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=banana – it does a google search for ‘banana’ and outputs the results in a format known as JSON. Somewhat similar in principle to XML, it’s basically a standard way of outputting sets of data, each of which has a type and a value. Normally if you want to take data from a text file and turn it into something you can manipulate in a program, you need to go through the long and boring task of writing methods to read a file, split it up, and work out what each section means.

Enter Jackson. Jackson is a fantastic library which does all the hard work for you. All you have to do is give it the JSON text, set up some classes which match the the data that’s included in it, and set it to work. Android does actually have it’s own JSON parser built in, but it’s not as simple to use, and apparently not as efficient. Jackson works just fine with Android though, so it’s easy to implement in your apps. There’s a basic tutorial over at the Jackson website (I’ll post it at the end of the post) which covers the basics, and it’s pretty simple. Firstly, you need to set up a class that will hold all the data from the JSON output. For example, if you had an output that had a list of people’s details, you’d want a Person class. In this class you just need to have parameter declarations which match the names of each item in the list, and getters and setters for each parameter. Google’s one outputs a bunch of stuff that you don’t really need, but you can just tell it to ignore anything you don’t define.

private double lat;

public double getLat() {
return lat;}
public void setLat(double lat) {
this.lat = lat;}

To get the results from the internet you need to set up an InputStream  with a HttpClient

public InputStream getJSONData(String url){

DefaultHttpClient httpClient = new DefaultHttpClient();
URI uri;
InputStream data = null;
try{
uri = new URI(url);
HttpGet method = new HttpGet(uri);
HttpResponse response = httpClient.execute(method);
data = response.getEntity().getContent();
}
catch(Exception e)
{
e.printStackTrace();
}

return data;

}

The code to turn the data into Java objects is so simple it hurts, assuming you have your classes set up correctly.

Reader r = new InputStreamReader(getJSONData(“http://ajax.googleapis.com/ajax/services/search/local?v=1.0&q=”+request+”&sll=”+lat+”,”+lng));
ObjectMapper mapper = new ObjectMapper();

mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ResponseData responseData = mapper.readValue(r, ResponseData.class);

Results result = responseData.getResponseData();
results = result.getResults();

Thanks to the long result strings Google gives, it took 3 classes for me to get it to read it correctly. The ResponseData class just has a single Results item in it, and this then contains a list of Result items. There might be a simpler way to do it, but I was getting all sorts of errors any other way I did it. I set it to ignore ‘unknown properties’ (that is, anything that I haven’t defined in my classes) for 2 reasons – one, I don’t need all the data it gives you, two, it just failed to read one of the parameters (GsearchResultClass) no matter what I did. I’m not sure why, possibly to do with the capitalisation, but either way, I decided to just skip it.

If it all goes correctly. it should give you a list of result objects, which you can then use the getters you defined to get all your data out of it. Simple. The search URL for the Local search is a bit different -

http://ajax.googleapis.com/ajax/services/search/local?v=1.0&q=PLACE TO SEARCH FOR&sll=CO-ORDINATES TO SEARCH NEAR

for example

http://ajax.googleapis.com/ajax/services/search/local?v=1.0&q=train&sll=50.00001,-5.00001

Next I added a search box to my map screen, and set it to search when you hit the OK button

button.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {
double lat = p.getLatitudeE6()/1E6;
double lng = p.getLongitudeE6()/1E6;
results = gs.runJSONParser(URLEncoder.encode(edit.getText().toString()),lat,lng);
OverlayItem oi;
GeoPoint gp;
int lati;
int lngi;
itemizedoverlay.clearOverlays();
for(Result rs : results)
{
lati = (int)(rs.getLat()*1E6);
lngi = (int)(rs.getLng()*1E6);

gp = new GeoPoint(lati,lngi);
oi = new OverlayItem(gp,rs.getTitleNoFormatting(),rs.getStreetAddress());
itemizedoverlay.addOverlay(oi);
}
}

Here, we’re getting our current location, and the string in the search box, and passing it to our search function. Note that you need to convert the search string to a URI. This is the format of a web address, but essentially what this does here is convert any characters that a HTTP query can’t handle and convert them into something it can – for example converting a space into %20.

The Next Step:

I’m pretty much done with the back end stuff now, and I’ve got all the data I need. There are two other parts to the project -

  • Create a custom database so I can add my own locations to it
  • Turn it all into an augmented reality application

For those unfamiliar with the term augmented reality – it’s all the rage these days, applications that take your camera view, and overlay things on top of that. The idea of this app is that I’ll take this location information from Google, and overlay that on the camera, roughly at the location of the buildings.

I’m not really sure where to start with this, so it’ll be interesting. Over the last few days, I’ve been able to read up on the basics on various tutorials. Today I was getting to the point where there just wasn’t any information out there. There are obviously applications out there that do use Google search functionality, but most aren’t willing to share their experience. Along with that, Google doesn’t like people accessing search results directly via Android, so there’s no documentation for it.

Tomorrow’s Goal

Hard to say anything specific. I’ll have a look at setting up a Camera view and see what I can do with it.

Links of the Day

http://www.softwarepassion.com/android-series-parsing-json-data-with-gson/

This refers to using the GSON library for JSON parsing, which works similarly to Jackson, but is apparently slower.

http://wiki.fasterxml.com/JacksonInFiveMinutes

Jackson’s basic tutorial. Explains the basics very well.

http://code.google.com/apis/ajaxsearch/documentation/#fonje

Explains how to use Google’s search API and some basics of how to call it in Java.

As usual, feel free to leave a comment or email android@lc8n.co.uk if you need any further information. Interestingly this blog has had 40 hits today, and I’m not sure where from. I’ve been tagging it here and on twitter, but I have all of 5 followers on Twitter (ProbablyJoe if you feel so inclined) and I’ve given this link to about 5 people. Interesting.

Posted in Android. Tags: , , . 3 Comments »

Day 3: Overlays and Geocoding (Pt 2)

Right, so I didn’t get to see the movie because it was all sold out, but I did get to take my phone for a stroll around town to see if it knew where I was. It did.

Mostly.

Today’s Results

As I said in the previous post, the built in address location stuff is very simple, but not as accurate as I’d like. Here’s what I get for my house (I worked out how to screenshot my phone!)

First thing to note: No, my house is not so huge that it takes up 40 street numbers. It does in fact just have one number in that range. Unfortunately, the ‘reverse geocoding’ method is only able to give you this level of accuracy.

As yesterday, the pointer isn’t entirely accurate, but I’m inside and it’s still very close (about 10 meters off)

The direction pointer is using the built in compass. This is only correct if you’re holding it in portrait mode and the correct way up. I need to work out how to change this for landscape mode.

The first two ‘issues’ there are not specific to my application though. If I show the same screen in the built in Google Maps application:

One issue I did run into is that it was -extremely- laggy, to the point where I had to kill it and reload it every few minutes. I think this is just down to the fact that I’m making it create a pop up message every time the location changes. Ideally I’d put this in another overlay, I just put it in a popup for testing, because the Toast function is nice and simple to use. Yes, Android’s popup class is called Toast. I know when I was doing this for showing the compass direction (which changes even more often) it crashed in a matter of seconds, so it should be fine if I remove that.

The Code:

The first thing was getting the orientation. This is actually really simple, though the issue was displaying it. Similarly to getting the location, you create a sensor listener, and you tell it what to do whenever the values from a specified sensor (the compass, in this case) change. This is where it became a bit confusing – I thought I wanted to rotate the marker when this happened, but actually this wasn’t the case. All I wanted to do was get the value, and then use them when I drew the marker. It sounds pretty much the same, but it works out quite differently.

I spent a lot of time finding a different way to show my marker on the screen. Android has plenty of built in ways of doing this for you, either by using a MapOverlay, which binds a marker to specific co-ordinates, or the built in MyLocationOverlay, which does all the work for you and puts a marker right where you are. However, since I want to display the direction we’re facing, I need to be able to rotate this marker. There’s no built in method for this with the MapOverlays, and in fact you can’t rotate a ‘drawable’ – that is, an image that’s stored within the program, at all. Firstly, you need to change it to a bitmap, then use a matrix to rotate it. We also need to know where on the screen to put it. Currently we just know where in the world we want it to point to. Good news is, there’s a simple method to convert that to a pixel co-ordinate on the screen too. Here’s all the code to do it.

Paint paint = new Paint();
Point pt  = new Point();
mapView.getProjection().toPixels(p, pt);

Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.pointer);

Matrix matrix = new Matrix();
matrix.postTranslate(-25, -25);
matrix.postRotate(ori);
matrix.postTranslate(pt.x, pt.y);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);

canvas.drawBitmap(bmp, matrix, paint);

First of all we’re getting our pixel location, then we’re converting our image to a bitmap. The first matrix translation is essentially centering the image, so it’s rotated around this point. If you don’t do this, it rotates around the top left corner, which is no good. Then we’re rotating it by the orientation – this is obtained from another section which gets the value from the sensor. Fortunately they’re both float values of degrees, so they go together just fine. Then we move the rotated image to our location. We anti-alias and filter the image to make it look nice, then we draw it using these settings.

A lot of coding in Android revolves around telling it what to do when events occur. These events generally have functions already coded in, so what we have to do is override those functions and tell it what we want to do when it occurs. In the above case, we’re overriding the draw function, which is refreshed pretty often.

@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow)

The next step was to get my location. I thought this would be quite complex, but Android has another nice built in method known as the Geocoder. What this does is take in latitudes and longitudes, checks some magical database somewhere, and spits out an address. We already have the latitudes and longitudes from our GPS, so that’s nice and simple.

List<Address> address = gc.getFromLocation(loc.getLatitude(), loc.getLongitude(), 5);
Address add1 = address.get(0);

It returns a list of addresses, but in practice I’m not sure why. Everything after the first result just seemed to only show one particular item, such as the city or county. But anyway, we get the first one, and from that we can get strings of each particular thing we want. It’s as simple as add1.getPostalCode() for the post code, and so on.

The Next Step:

Unfortunately, this isn’t as accurate as I’d like it to be, and I really need specific information about individual buildings, such as those that Google Maps provides on the internet. Unfortunately, Google doesn’t let you have this feature directly in the Android APIs, presumably because they don’t want people making free satnavs. There is another way though. Fortunately Google has a bunch of APIs for searching, and they return results in a format called JSON. This uses JavaScript, which I’ve never really looked at, but the end result is that it gives you an output with all the information you need. It’s a similar sort of format to XML but supposedly easier for programs to read.

So in this case, I won’t be getting the information from the built in functions, but requesting it from a web site. From there, it should be fairly simple to put the information on the map.

Tomorrow’s Goal

Be able to search for specific locations via Google, and overlay them on the map.

Links of the Day

http://www.androidcompetencycenter.com/tag/map-overlay/

A useful tutorial on creating overlays on maps

http://www.developer.com/java/j2me/article.php/3748281/Working-with-Images-in-Googles-Android.htm

Misc information about how Android handles images

http://blogoscoped.com/archive/2008-12-15-n14.html

I posted this yesterday too for the location stuff, but it also has a section about Geocoding.

Note that anything you find about the googlenav class is no good now. Google removed this functionality a few versions ago.

http://www.anddev.org/resize_and_rotate_image_-_example-t621.html

The correct way to rotate and resize images! (rotating the canvas is not correct)

If you have any questions

Posted in Android. Tags: , , . 2 Comments »

Day 3: Overlays and Geocoding (Pt 1)

Just a quick update, I’m about to go out and test my app on the open road! Also go and see Clash of the Titans, but it seems like a good opportunity to test it on a location besides my own house.

Today has again been pretty productive, and I’ve managed to meet my own goals. The location pointer now rotates with your compass direction, and there’s also a small display of your current location.

The first half of the day was spent going in circles, trying to get the marker into a format that I could rotate. Once I had that all worked out correctly, it was fairly simple to add that in, as the hardware gives you your degree of rotation, and this can be directly applied to an image.

Location information was also easier than I expected, at least to a point. It seems like you don’t have full access to all the information that you’ll see on google maps itself, though it is -extremely- easy to take a co-ordinate, and get an address from it.

Now to see what it gives in some other places.

No pictures as of yet since it doesn’t seem to work with the emulator, but I’m planning on taking a camera with me to take pictures of the phone in action.

Day 2: MapViews and Locations

After yesterdays post, I dived headfirst into Android, with my only experience being a few hours doing basic examples, 6 months ago.

Needless to say, it took a while to get used to it again. Android is Java based, but also uses some XML for layouts. It takes some getting used to, but fortunately the API is pretty well documented. I spent a while not having a clue how to do anything, but after a while I caught up again.

Android is updated pretty often. I got my phone 6 months ago, and it was on version 1.5. The newest phones are being released with version 2.1, and there’s been 3 other versions in between. This is great because it means Google is adding new stuff all the time, but it’s also confusing because they’re also changing old stuff. Consequently, half the tutorials I’ve read are actually outdated, so it’s been difficult trying to work out why things aren’t working.

Anyway, by the end of yesterday I’d worked through a few tutorials and had a general idea of how to use Android again. Today I wanted to make some progress with the Google Maps API, and hopefully get it showing my location, and updating in real time.

Android applications work by displaying ‘Views’. These are basically layouts that are created with an XML file. Although, since I’m working with the Map view today, there’s not really any layout work to be done, and I just want a screen full of map. Some controls such as zoom are handy too, and fortunately these are built into the MapView class.

Displaying a map is pretty simple. You have to get an API key from Google to be allowed to access their maps,  and then it’s as simple as a few lines of code:

mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(true);

The first line refers to the XML file, which supplies your API key, the second line says you want zoom buttons, and the third line says that you want satellite images. Removing this line would result in displaying plain road maps.

The result of this is a big world map which you can zoom in on. Not especially useful, but quite a lot for so little code. Thanks Google APIs.

The next step was to get my current location, and show it on the map. I ran into a few problems here, mainly because I was testing my application on the emulator. If you want your location data, you need GPS. Computers do not (generally) have GPS. Phones do. So if you’re testing it on your computer, you need to give it some fake GPS data. I read (incorrectly) somewhere that the emulator just supplied some fake GPS data automatically. Whether this was an old feature that removed, or this person was just wrong, I’m not sure. Eventually though, I found the DDMS screen in Eclipse, which gives you debugging information, and lets you supply data to the emulator. You can give it location data, phone calls, or even whole strings of locations for it to run through in a path.

Thanks to a combination of Google Maps (the internet version) supplying me with some strange numbers, and me getting my  latitudes and longitudes mixed up, I went from Ethiopia to Sweden to the middle of the Irish sea, and eventually got it to locate my house.

After a while of being confused, this turned out to be fairly simple too. Firstly you need to set up a LocationManager, which deals with getting your location information from some sort of ‘provider’.

lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

Firstly you need to tell it where to get the data from. You can do this by setting certain ‘criteria’ for the location data.

Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(true);
criteria.setBearingRequired(true);
String provider = lm.getBestProvider(criteria, true);

This is saying we want ‘fine’ accuracy, we do want to know our altitude, and we do want to know our bearing (compass direction) in fact, those last two points are unnecessary right now, since I just want to know my location, but later on I will be needing that data. In fact, this whole section is fairly unnecessary right now, because I know I want to be dealing with the GPS. Alternatively you could use the mobile network to get your location – it’s less accurate but uses less power. There are also ways to combine the two for more accuracy. But in the end, the getBestProvider function just gives you a string which points you towards the provider. I could just supply “gps” manually here

lm.requestLocationUpdates(provider, 10000, 0, ll);

This tells the phone that we want our location to be updated regularly. provider is the string we got before, in this case “gps”, 10000 is the milliseconds between updates (initially I just set this to 0, and it basically crashed my phone because it was updating too much. In this case it’s 10 seconds, though it’s not entirely accurate. I’ll probably want it lower later on). The third argument allows us to say we only want to be updated when the location changes by x number of meters. With the nature of my application, I want to know whenever the location changes, so this is set to 0. The final argument is a LocationListener, which is an interface we need to add, which defines actions to be carried out on some location-specific events. The important thing here is that we want things to change on the screen whenever our location changes.

private class MyLocationListener implements LocationListener
{

public void onLocationChanged(Location loc) {
if (loc != null) {
mapView.invalidate();

int lat = (int)(loc.getLatitude()*1E6);
int lon = (int)(loc.getLongitude()*1E6);
float bear = loc.getBearing();

GeoPoint p = new GeoPoint(lat,lon);
mc.animateTo(p);
mc.setZoom(21);
OverlayItem currentLocation = new OverlayItem(p,”You are here”,”Hi there”);

itemizedoverlay.addOverlay(currentLocation);

}
}

What’s happening here is that whenever the location changes, it resets the map, moves to the location, zooms in, and places a marker there. For some reason the GeoPoint object uses ‘microdegrees’ while general latitude and longitude measurements are in degrees with many decimal points. So it’s being multiplied by 1E6 (10^6 or 1000000) to get it into the correct format.

I had a few issues with trying to get it to just move the marker rather than make a new one every time it updated, but I got there in the end. Next step is to get it showing the direction correctly (hence the .getBearing() function in there).

I then gave it a whirl on my phone, and it was working well. It pinpointed my location pretty accurately, which is good to know. I don’t have a camera to hand to show it working on my phone, but I can show some screenshots of the emulator.

That’s my house! It’s quite accurate here – I’m actually around where the little guy’s arm is, but GPS isn’t so accurate inside. If I go outside it’s a bit more accurate. This should be more than accurate enough for my application anyway, as it’s for outside use anyway. Also, it turns out that the MyLocationOverlay class does a lot of the stuff here for you. When I put both my own function and the MyLocationOverlay on the map though, they were almost identical, and at least I learned some things from this. MyLocationOverlay also displays the accuracy, and can give you a compass.

Note: Since this is my University project, I’m not going to put all the source code on here, and the bits I do paste will probably be fairly useless on their own. If you do happen to come across this page looking for information though, I’ll post some links that were helpful each day. You can also email me questions at android@lc8n.co.uk

Useful information for the day:

The HelloMapView tutorial on the Android Developer site is a great place to start:

http://developer.android.com/guide/tutorials/views/hello-mapview.html

Be sure to follow all the instructions for getting an API key! If you don’t get this right you won’t see any maps. You need to run the keystore program and then enter this string into the website. You can use the debug key for everything until you plan on adding your app to the market.

http://code.google.com/android/add-ons/google-apis/mapkey.html

This is a useful tutorial. A lot of it deals with using the address book and converting addresses to GeoPoints, but there’s some useful stuff there

http://blogoscoped.com/archive/2008-12-15-n14.html

This is another useful tutorial about GPS functions. Note that you need to click on the “Listing” links to get the source code. Some of it didn’t work quite right for me, but if you’re using Eclipse it should have a fairly good idea of how to correct it.

http://www.devx.com/wireless/Article/39239/0/page/1

Tomorrow I plan to try and add orientation/bearing data, and maybe see if I can get data from Google Maps about specific addresses on there.

Race against time

Right, it’s been over a year since I updated this blog, and now I’m going to revive it. Here’s why.

I currently have 1 month left until the deadline for my final university project. I haven’t started coding it yet. It’s going to be a long month.

I’ve decided to document the development progress, partially since it’ll make it easier when it comes to writing the final report at the end, partially for my own amusement, and partially in the hope that could be of interest to other people if the project goes as planned.

The project I’m working on is a mobile application for Android. Android is Google’s answer to the iPhone, their own mobile OS which has been building momentum rapidly over the past year, and is the power behind some of the best  new mobile phones, such as the HTC Desire.

The basic idea of my application is that you take your phone, you point it at a location, and it tells you what you’re looking at. My original idea was to use image recognition to work out what you’re looking at through the camera, though this turned out to be far too complicated. It was then suggested that I could use the phone’s built in GPS and compass to reach a similar result. The location could then be compared to a database, either custom made or freely available (such as Google maps) to get location information.

Then I found out it’s been done before, by Layar. But, I was commited to it by this point, so I decided to go ahead with it.

Layar has evolved into a very popular application with a large team working on it. I have 1 month and 1 person to create something similar. It’s going to be a busy month.

Follow

Get every new post delivered to your Inbox.