Building the Casa de Balloon Tracker App 2018 Edition

In order to track our weather balloon payloads and capture near-space photos, the Casa de Balloon Club uses Android phones running our own tracker app.

You can read about how the original version of this application was implemented here. The purpose of this post will be to discuss changes we've implemented to deal with newer versions of Android and lessons we've learned along the way.

Android Studio 3 and Kotlin

Since it's 2018, we decided to get with the times, upgrade to the latest version of Android Studio, and switch our app code from Java to Kotlin. While it sounds painful to switch from one language to another, Android Studio actually makes it quite easy - because it is built on top of IntelliJ IDEA, we simply copied our old Java code, pasted it into new Kotlin files, and let the IDE translate our Java into equivalent Kotlin.

While the Java-to-Kotlin translation is not perfect especially when applied to larger blocks of code, it is incredibly convenient and is a very nice way to learn Kotlin if you already have experience with Java. Speaking of learning Kotlin, we also very much recommend working through the Kotlin Koans.

Foreground Service

One of the biggest functional changes we made to the tracker app is to implement all of the main interval loops (photos, SMS location updates, HTTP location updates) as TimerTasks within a single foreground service.

By using a foreground service, our application is generally spared some of the more aggressive power management and security restrictions that are applied to background services and alarms. Also having the notification show up while the service is running provides a nice confirmation that our app is running properly.

One compatibility note - starting with Android O there is an explicit method to start a foreground service - "startForegroundService", while older version of Android should use "startService". Here's an example of using "Build.VERSION.SDK_INT" to choose the right method, allowing our app to run on a variety of Android versions.

Photo Storage

Another change introduced with Android 4.4 KitKat was clamping down on the ability of apps to write to anywhere on external / removable storage. For security reasons, applications are instead largely restricted to writing to their own specific directories created within external and removable storage.

It's pretty easy to get *any* location to save photos and logfiles, but figuring out the correct location which corresponds to a removable SD card is a bit more tricky and involves a couple different APIs depending on the version of Android you are targeting. Samsung devices prove to be particularly tricky as they report both external SD cards and a part of their internal storage as available external storage locations, and it's up to you to look at an environment variable to tell which one is actually the SD card.

Our new tracker app implements a getStorageRoot method that tries a couple different ways to figure out what the actual SD card storage location is and return a path which can be written to.

Background Camera

Taking photos in the background has become increasingly difficult due to Android security and power management measures. In later versions of Android, only foreground Activities and foreground Services may access the camera. Fortunately we already switched to using a foreground service!

Unfortunately one of the requirements of most Android camera devices is that you activate a preview before taking a photo. In the previous version of the tracker app, we accommodated this by launching a dedicated photo Activity which then displayed the preview live before taking the photo and closing. This turned out to be less than reliable, especially on newer versions of Android that actively try to prevent random apps from hijacking your screen and attention.

While almost every Android camera tutorial has an example of connecting the live preview to a SurfaceView widget which displays on the screen, we discovered that you can just as easily route the live preview to a SurfaceTexture which simply stores the data in-memory and doesn't bother the user. With this little trick, our foreground service can go ahead and take photos without having to pop up anything to the user.

Sensors

Our earlier tracker app completely ignored all the awesome sensors crammed into these little pocket computers we call phones. Fortunately Android has a whole framework for identifying which sensors are present on a device and reading values from them.

In addition to logging position via GPS, the most interesting sensors for us are the environment sensors - specifically pressure, relative humidity, and ambient temperature.

Pressure sensors (barometers) are rather common in flagship phones over the past couple years, and can be used to determine altitude in the event a GPS fix is lost due to altitude restrictions.

Relative humidity and ambient temperature sensors are much more difficult to find - in fact, the only phone we've come across which has these sensors is the Samsung Galaxy S4.