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.

Follow

Get every new post delivered to your Inbox.