Build your own tracking app

Snap and Track

Article from Issue 183/2016

Build a simple and handy solution for recording and tracking locations; in the process, learn how to automate Android and build a simple Python-based app.

A dedicated GPS tracker or a GPS tracking app can come in handy in many situations. Recording and saving your movements can help you geocorrelate photos, keep track of places you've visited, maintain a simple travelogue, and more. Although several excellent apps can be used to transform an Android device into a capable GPS tracker, most of them are one-trick ponies designed to record your location continuously and save the geographical data in the GPX format.

What if you need a tool that does more than that? For example, suppose you want to use your Android device to snap a photo and then save the relevant data – such as date and time, latitude and longitude – in a database or a text file. Wouldn't it be great to have a web-based app that runs on a Linux server and lets you view your snapshots and data using a regular browser? If you have a working knowledge of Python scripting, you can build a tool like this yourself, and this article shows you how to do that.

General Notes and Preparatory Work

The solution you are about to build (I'll call it Geofix) consists of two parts: (1) a simple Python script running on the Android device that automates the process of taking snapshots, collecting the relevant data, and saving it in an SQLite database and (2) a Python-based web app that acts as a front end for viewing the snapshots and the data in the database.

Android doesn't natively support Python scripting, so to run Python scripts on your Android device, you need to install the Scripting Layer for Android (SL4A) and Python for Android packages on it. To do this, grab the latest APK packages of SL4A [1] and Python for Android [2] for the appropriate architecture and install them on the Android device.

Most mainstream Linux distributions come with Python installed by default. That means any machine running a popular Linux distribution like Debian or Ubuntu can be used to run the Geofix web app. Instead of writing a web app from the ground up, you can save a lot of time and effort by using a dedicated web framework. You can choose from several excellent Python web frameworks, and Bottle [3] is probably the simplest and most lightweight of these – which makes it a perfect tool for building the Geofix web app. To install Bottle on a Debian or Ubuntu-powered machine that will serve the web app, run the following commands as root:

apt-get install python-pip
pip install bottle

Although Geofix is a relatively simple solution, listing all of its code here is not very practical, so before you proceed, grab the latest version of Geofix [4] from the GitHub repository or clone it using:

git clone

The Android Python Script

With all the pieces in place, you are ready to dissect and study the Python script that runs on the Android device. This relatively short and simple script performs several actions. To keep things tidy and organized, the script uses dedicated directories for storing the database and snapshots.

The script starts by checking whether the directory specified as a value of the geofix_dir variable exists. If the directory doesn't exist, the script creates it, along with the snapshots sub-directory for storing photos:

if not os.path.exists(geofix_dir):
    os.makedirs(geofix_dir + 'snapshots/')

Thanks to so-called facades (friendly wrappers for Android APIs), the SL4A and Python for Android can access and make use of various Android functions. The script uses three facades to toggle location features and obtain geographical data:

droid = android.Android()
droid.eventWaitFor('location', int(wait))
location = droid.readLocation().result

The startLocating() facade enables the locating functionality, the eventWaitFor() facade pauses the script for the period of time specified in the wait variable to obtain geographical data, and the stopLocating() facade disables locating. The period of time required to obtain geographical data depends on several factors, and you might need to adjust the default wait value to give the script enough time to receive the data.

Instead of modifying the wait value in the script, you can add a dialog that lets you specify the wait time on the fly. To do this, replace the wait = 9000 line with the following code:

droid = android.Android()
droid.dialogCreateAlert("Wait time")
wait = droid.dialogGetInput("Specify wait time in milliseconds:").result

The locating functionality in Android uses two sources to obtain geographical data: the built-in GPS module and mobile network. This ensures that the device is able to obtain the data even if one of the sources is not available. The code block shown in Listing 1 takes care of extracting latitude and longitude values from the received geographical data.

Listing 1

Obtaining Latitude and Longitude Values


The script first attempts to obtain latitude and longitude values from the network source (lines 1-5). If this fails, the script tries to extract coordinates from the GPS source (lines 7-11). Next, the script constructs a string containing the coordinates in the digiKam-compatible format (see the "Geotagging Photos in digiKam" box) and a URL that shows the exact location on the OpenStreetMap map:

Geotagging Photos in digiKam

If you happen to use digiKam as your preferred photo management application, you can use it together with Geofix to geotag photos. Both and scripts save the geographical coordinates in the digiKam-compatible format. So, to geotag one or several photos in digiKam, just copy the desired coordinates in the digiKam format (e.g., *geo:56.1831455,10.1182492*) from Geofix. Then, switch to digiKam, select the photos you want to geotag, and choose Image | Geo-location. Select the photos, right-click on the selection, and choose Paste coordinates.

digikam = 'geo:' + lat + ',' + lon
osm =  '   index.html?mlat=' + lat + '&mlon='   + lon + '&zoom=18'

The current date and time, latitude, longitude, generated digiKam string, and OpenStreetMap URL are then saved in the geofix.csv comma-separated file (Listing 2).

Listing 2

Saving Coordinates


In addition to the comma-separated file, the script also writes the data into the geofix.sqlite SQLite database, which the web app uses as its back end (Listing 3). If the database doesn't exist, the script creates it before writing the data into it (Listing 4).

Listing 3

Writing Data to geofix.sqlite


Listing 4

Creating the Database


Finally, the script takes a photo using the cameraInteractiveCapturePicture facade. The photo is saved in the dedicated snapshots directory using the date and time stamp as the photo's file name:

droid.cameraInteractiveCapturePicture(geofix_dir + 'snapshots/' + dt + '.jpg')

To install on your Android device, put it in the sl4a/scripts directory. Although you can launch the script through the SL4A app, you can also create a shortcut to the script on the home screen. This way, you can run the script with a single tap.

Scripting with Termux

The SL4A and Python for Android combination is not your only option for automating Android. The Termux project [5] equips Android with a terminal emulator and Linux environment. Among other things, this means you can automate Android using Bash shell scripts that make use of popular Linux tools. Better still, the Termux:API add-on enables access to Android's APIs, so you can integrate Android functionality into shell scripts.

Both Termux and Termux:API are available on Google Play Store and F-Droid, so you can install the apps from your preferred source. To replicate the functionality of the Python script, you need to install a couple of Linux tools, including termux-api, which enables Termux:API functionality, jq for manipulating data in the JSON format, and sqlite for working with SQLite databases. To do this, launch Termux and run the following commands:

#apt update
#apt upgrade
#apt install termux-api jq sqlite

The script that automates the required tasks is not particularly complicated, but a couple of commands need some explanation. The termux-location command outputs location data in the JSON format, and to extract latitude and longitude, the script needs to pipe the output to the jq tool:

lat=$(termux-location | jq '.latitude')
lon=$(termux-location | jq '.longitude')

The termux-toast command can only display text from stdin (the standard input connection), so to show a pop-up message, you need to pipe it to termux-toast using the echo command:

echo "Coordinates: $lat, $lon" | termux-toast

The termux-camera-photo command requires a camera ID value assigned to the -c or --camera parameter. Usually, the back camera has ID 0, and the front camera has ID 1. To check the IDs of the cameras on your Android device, run the termux-camera-info command.

Termux lets you automate tasks on Android using the environment and tools familiar to most Linux users, but it does have a couple of drawbacks compared with SL4A and Python for Android. To run the script (or any Bash shell script for that matter), you need to start the Termux app first and then execute the appropriate command. This can quickly become a serious nuisance if you use the script often. Also, the termux-camera-photo command doesn't provide any visual feedback, and you have no control of shooting settings.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus

Direct Download

Read full article as PDF:

Price $2.95