Wednesday, February 20, 2008

Location providers - climb the Triglav with Android

Android SDK as it is clearly encourages developers to deal with location-aware applications. Both the location provider and the map part of the system is sufficiently documented and is functional which is pretty much in contrast with e.g. the synchronization and bluetooth parts. Good tutorials have been written about how to use the Android location framework so I wanted to try something else. I wanted to see, how to introduce one's own location data into the system.

Android SDK comes with one built-in location provider called "gps". This location provider moves along a predetermined route - obviously around Google premises. I was curious whether it is possible to introduce one's own location provider into the system therefore I took apart android.server.LocationProviderService. I found that it is relatively easy to introduce one's own location track which is then presented as new location provider to Android applications. Creating a new location provider software module turned out to be more complicated and eventually I did not try that out. LocationProviderService is able to handle location providers with their own Java logic but unfortunately the classes of these providers are loaded by the own classloader of LocationProviderService. This means that it is not possible to deploy the location provider software module as a package (apk), one has to fiddle with the software base of the Android system.

I did not do it because, to my pleasant surprise, Android's own location provider turned to be a pretty versatile simulator itself. Deploying own location providers based on track data really works like a charm. The LocationProviderService loads providers from under the /data/misc/location directory (device-based path). Each subdirectory under this directory is a location provider and the name of the location provider equals to the name of the subdirectory. The files in the subdirectory define the provider. As an example, you can go to the tools subdirectory of the example program package and run pull_gps.bat (emulator needs to be running when you do this). This batch file will fetch the three files associated with the "gps" provider as gps_location, gps_nmea and gps_properties (their original names on the device are location, nmea and properties, respectively, under the subdirectory called gps). The properties file describes the properties of the location provider in an easy to understand textual format. The location file is the last known location and the nmea is the track info in NMEA format. Well, I am not familiar with location format and I don't know what NMEA format is. There are two other possibilities: instead of "nmea" file, you can have "kml" or "track". In case of "kml", the track data is in KML format while "track" is a very simple textual format. I went for the latter and didn't try the former one - erm, I left that execise to the interested reader. ;-)

You can download the example program from here.

The "track" format is simple. It looks like this:
time longitude latitude altitude [bearing speed]


test said...

I followed your steps. But I am unable to find triglav in my lovationproviderList.
Here is my console

D:\Android\android-sdk_m5-rc15_windows\tools>java ozitotrack -s20 triglavMT.plt triglav
Track length: 8.776666666666667 minutes (0.14627777777777778 hours approx.)

D:\Android\android-sdk_m5-rc15_windows\tools>pull_gps.bat triglav

D:\Android\android-sdk_m5-rc15_windows\tools>rem last known location

D:\Android\android-sdk_m5-rc15_windows\tools>rem String providerName = tokens[idx++];

D:\Android\android-sdk_m5-rc15_windows\tools>rem long time = Long.parseLong(tokens[idx++]);

D:\Android\android-sdk_m5-rc15_windows\tools>rem double latitude = Double.parseDouble(tokens[idx++]);

D:\Android\android-sdk_m5-rc15_windows\tools>rem double longitude = Double.parseDouble(tokens[idx++]);

D:\Android\android-sdk_m5-rc15_windows\tools>rem double altitude = Double.parseDouble(tokens[idx++]);

D:\Android\android-sdk_m5-rc15_windows\tools>rem float bearing = Float.parseFloat(tokens[idx++]);

D:\Android\android-sdk_m5-rc15_windows\tools>rem float speed = Float.parseFloat(tokens[idx++]);

D:\Android\android-sdk_m5-rc15_windows\tools>adb pull /data/misc/location/gps/location gps_location
2 KB/s (0 bytes in 77.000s)

D:\Android\android-sdk_m5-rc15_windows\tools>adb pull /data/misc/location/gps/nmea gps_nmea
180 KB/s (0 bytes in 11568.000s)

D:\Android\android-sdk_m5-rc15_windows\tools>rem (time> (long> (lat> (alt> [(bearing> (speed>]

D:\Android\android-sdk_m5-rc15_windows\tools>rem adb pull /data/misc/location/gps/track gps_track

D:\Android\android-sdk_m5-rc15_windows\tools>adb pull /data/misc/location/gps/properties gps_properties
12 KB/s (0 bytes in 193.000s)

android tutorials said...

Here's my own GPS android tutorial.

bern said...

Hi Gabor,

Does this mean I can add my own "coordinates" in which android will try and locate me?

As an example, Google Maps doesn't work quite well in my city. Following ur tutorial do you think I could add some locations from the city and have it working on an application?

Btw, have you tried skying in Pohorje? I heard its not the same as Triglav, but it's also a nice ride :)

Gabor Paller said...

bern, you misunderstand the example.

This example (which worked before the 1.0, I understand, nowadays there are problems with the test "gps" provider in the SDK) simulated the movement of the device in case of the SDK when no real movement takes place. I fed this Triglav hike into the test provider and presto, it worked. The purpose of this sample is to replace the GPS receiver for testing. It does not help you in real-life situation.

Saran said...

I need to add the own provider by using code instead of pushing location files.Can someone help me to do this?