On-Device Debugging Part I: Now It’s On, Now It’s Off
Tags: android
Published: 2019-06-24 01:45:41

---
title: On-Device Debugging Part I: Now It’s On, Now It’s Off
published: true
tags: android
canonical_url: https://zdominguez.com/2019/06/22/debug-options-toggles.html
---

Over the past year, my team have been steadily building a Developer Options screen for our app. It is a simple [`PreferenceScreen`](https://developer.android.com/reference/androidx/preference/PreferenceScreen.html) available on debug builds that aims to help us:

- figure out what’s going on without needing to be attached to a computer
- test various configurations without re-installing
- have a host for various experimentations we are trying to explore

In this series of posts, I will share what these various options are and how we made them.

(If you are not familiar with [`PreferenceFragmentCompat`](https://developer.android.com/reference/kotlin/androidx/preference/PreferenceFragmentCompat.html), I highly suggest to read about that first before proceeding. You can start with this [AndroidX guide](https://developer.android.com/guide/topics/ui/settings.html) on Settings.)

* * *

At Woolworths, we use [feature flags](https://en.wikipedia.org/wiki/Feature_toggle) a lot. It helps us merge our code to master quicker, allows our QA team to provide feedback faster, and helps manage the risks when doing an important release.

We use [Firebase Remote Config](https://firebase.google.com/docs/remote-config) to manage our existing feature flags, which enable us and our product owners to control these flags very easily.

Although it is very convenient to have these flags configurable remotely, it also makes it difficult to do a quick test on something behind a feature flag for someone who doesn’t have access to the console. It might also disrupt someone’s work if somebody else changes the flags’ values remotely without them knowing it.

It is for this reason that we introduced local feature toggles. This gives anyone on a debug build the ability to turn as many features on or off as many times as they want without affecting anyone else’s builds.

<center>
    <img src="https://i.imgur.com/tJWVINR.jpg">
    <br>
<small>Names changed to protect individuals :sweat_smile:</small>
</center>

On a fresh install, the app would use the [in-app default values](https://firebase.google.com/docs/remote-config/use-config-android#set-in-app-default-parameter-values) we have set and the override switch is OFF. The app would keep using the values provided by Firebase until the override switch is flipped.

And when it gets confusing and we want a do-over, the “Reset local to Firebase” button would turn the flags back to what is provided by Firebase.

<center><img src="https://i.imgur.com/Bz3DVdd.gif"></center>

All the features in this list are added dynamically from an enum that holds all our feature flags:

{% gist https://gist.github.com/zmdominguez/249ce5e262714edbd540cf10cea195d0 %}

There a few things at work to make all of this come together. First off, if the override button is OFF, we want everything related to feature flags to be disabled. This gives better clarity on what settings the app is using, and prevents the user from unwittingly changing a value.

To do this, we define the switch’s behaviour in our XML file:

{% gist https://gist.github.com/zmdominguez/742c20b873664d9e6e9895d3810b2d93 %}

The attribute `disableDependentsState` means that if this switch is OFF, any other value that depends on this preference gets disabled.

Next, we want to create a new category that will contain all of our feature toggles and belong to the same category as our override switch.

{% gist https://gist.github.com/zmdominguez/5e20ff3774491a39975994007307443e %}

We can then add each of our features into this `featureTogglesCategory`:

{% gist https://gist.github.com/zmdominguez/23adebb7578cbf9fb2dd88c9c3412f67 file=add_features.kt %}

For simplicity, we use the `Feature` enum’s name as the `SharedPreference` key for each feature toggle, as well as the label that appears beside the `Switch`.

What the function `isFeatureEnabled()` does is simply return Firebase-provided values for production builds, and figure out what the our preferences are for debug builds:

{% gist https://gist.github.com/zmdominguez/942772920292b941afe58ea7dc8a2047 %}

Now that we have prepared our feature flags `PreferenceCategory`, we can route our dependency on our override switch:

{% gist https://gist.github.com/zmdominguez/6f7d540e8451612e10a3703af1ceeedf %}

It may seem turned the other way around, but that is correct. :white\_check\_mark: To set this new category as _dependent ON another preference_, we need to call [`setDependency()`](https://developer.android.com/reference/kotlin/androidx/preference/Preference.html#setDependency(kotlin.String)) and give it the name of that control preference.

As for our “Revert…” button, we also want it to be disabled if the override switch is off (because it doesn’t serve any real purpose in this case):

{% gist https://gist.github.com/zmdominguez/ebf448be8f09bb267a30bd32b8c2e2bd %}

And to handle user clicks on this button, we set up a callback in our `PreferenceFragment`:

{% gist https://gist.github.com/zmdominguez/c45aa2178ee0720a7be87aed0a816d0a %}

And that’s it! We have dynamically added a set of switches to our `PreferenceScreen` that would hopefully make testing our app much easier.

In the next post in the series, we will talk about more on-device debugging tools such as managing our `SharedPreferences`, and showing device information, among others.