On-Device Debugging Part V: Strut Your Stuff

20 Jul 2019 | tags: android

Over the past year, my team have been steadily building a Developer Options screen for our app. It is a simple PreferenceScreen available on debug builds that help us:

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

Read the other posts in this series:

(If you are not familiar with PreferenceFragmentCompat, I highly suggest to read about that first before proceeding. You can start with this AndroidX guide on Settings.)


Working on an app means we are constantly tweaking how things look. Change this shade of green, use this widget instead of that, move this thing to there.

In the last part of our on-device debugging series, we look at some of the ways we showcase how things should look in our app.


Design Playground and Shortcuts

Design Playground

A few weeks ago, we went all in and switched our whole app to use the new Material Design Components theme. (Nick Rout has an awesome article showing you more details on how to do this for your app.)

We fully expected that some widgets might look strange and we might have to tweak some things a bit. Taking inspiration from the MDC Catalog app, we came up with a Theme Showcase page.

This page has all the widgets as well as the custom components we use throughout the app.


Widget showcase

This has been really useful in helping us figure out how things look as we go through adapting MDC. This page has also been handy when we are tweaking something with our design team, and as a reference page for when we are visually testing a new feature.

Since we also have multiple themes in the app, we included a theme switcher that allows us to see how everything looks in each of the themes.


Dynamically switch themes

This switcher is accessed through the overflow menu. When the user chooses a theme, we save the value to a SharedPreferences file.

For simplicity, we only save the position of the chosen theme:

We then need to make sure that we get back the chosen theme:

And set it on our Activity’s onCreate via setTheme().

Shortcuts

Some parts of the app are a bit cumbersome to get to.

When we were building our app’s order confirmation page, it was getting annoying having to complete an order each time to see how it looks whenever we change something in the layout.

As we saw in my previous post about app shortcuts, we can put in a targetPackage and a targetClass in our Intents:

Having these shortcuts available helped us skip having to navigate through multiple steps to get to a particular screen.


And with that, we wrap up this series on on-device debugging options. We have seen how we can make feature toggles more user-friendly, how we can surface stacktraces for quicker debugging, and how we can retrieve Logcat traces out of our testers’ devices.

Thank you for sticking with the series, and massive thanks to everyone who has given me their time helping get these posts through! :green_heart:


On-Device Debugging Part IV: Log All The Things!

08 Jul 2019 | tags: android

Over the past year, my team have been steadily building a Developer Options screen for our app. It is a simple PreferenceScreen available on debug builds that help us:

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

Read the other posts in this series:

(If you are not familiar with PreferenceFragmentCompat, I highly suggest to read about that first before proceeding. You can start with this AndroidX guide on Settings.)


As I mentioned in part II, we leverage Timber a lot. Those stacktrace log screens have been really useful when the app misbehaves, but what about those times when we just want to have checkpoints whilst using the app?

Enter our next set of developer options:


More debugging!

Show Debug Toasts

Toasts are a great way of setting visual checkpoints in an app. They are relatively unobtrusive and easy to create.

Enabling “Show debug Toasts” in our developer settings allows us to surface these checkpoints when we are testing something unpredictable:


I previously talked about a geofencing feature we had to implement, and we have that feature to thank for spurning the idea for this debugging feature.

In this feature, we want the app to notify the user when they enter a geofence. Testing geofences in the middle of the city can be tricky, and having visual cues that let us know if we have entered or exited a geofence has been super helpful for us.

This function lives in our DebugExtensions class:

(In this case, SettingsInteractor takes care of exposing some of the debug options that our main source set needs access to.)

Having a developer option toggle to control this means we can turn the Toasts off when it gets too annoying, and we lower the risk of leaving a debugging Toast when we release to production as well.

Enable Leak Canary

We have some really old Activities in the app that drive Leak Canary crazy. Until we get around to cleaning them up, it also drives our QAs crazy. This toggle gives them the power to turn the tool off so they can test in peace.

As a rule, developers keep this toggle on during active development. As for those old Activities, we are in the process of reworking them to make them perform better.

Show Debug Notification

When enabled, the app shows a persistent notification that serves as the shortcut to this Developer Settings screen (we also provided an entry to this screen in our app’s junk drawer aka the “More” menu for debug builds). Pretty straightforward.

Logs

When connected to our development computers, we have a wide array of debugging tools at our disposal. We can use Timber, or System.out, or Toasts, or breakpoints, etc.

But going back to our geofencing feature, all of these options are not really viable to us during testing. Sure we can walk around Surry Hills with a laptop and keep an eye on Logcat whilst debugging. But we really can’t expect everyone who is testing the app to do this.

When this option is turned on, we send all the Logcat information from our app into a text file:

Getting those logs out of a particular device can be fiddly, dealing with multiple OEMs and USB variations. And those logs are pretty useless just sitting there, so we put in the option to send those files to us:

Using ACTION_SEND_MULTIPLE with the Intent allows us to automatically attach all the log files we can find in the user’s debug file storage.


Gimme those logs!

Depending on the email client they choose to send the files with, they can remove or add more files as they please.

To be good citizens, we have also provided the option to clear all existing logs so that users can reclaim their precious storage space.

Out of all the debugging features that we have, this one is probably my favourite. :green_heart:

(Massive thanks go out to @ataul for all his patience reviewing my crazy ramblings :laughing: )


In the next post, we will look at how our developer settings help us work better with the designers in our team. Stay tuned! :radio:


On-Device Debugging Part III: Inspect, Reset, Repeat

01 Jul 2019 | tags: android

Over the past year, my team have been steadily building a Developer Options screen for our app. It is a simple PreferenceScreen available on debug builds that help us:

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

Read the other posts in this series:

(If you are not familiar with PreferenceFragmentCompat, I highly suggest to read about that first before proceeding. You can start with this AndroidX guide on Settings.)


A lot of things affect how the Woolworths app behaves. Sometimes databases get out of sync between production and development environments, there are one-shot screens and tooltips, the UI may look different based on device qualities, or even changes to available options to users based on the type of account they have.

To manage and keep track of all these things, we included a set of actions in our developer options.


Additional actions

Environment Switcher

We have a few different environments that the apps can use. Having a switcher built into the app means we can easily test our app’s behaviour on any of the available environments.


Switcher confirmation

For us, switching environments mean revoking access tokens and everything else that come with that. Since this is a destructive action (they would need to log back in), we opted to present a confirmation dialog before proceeding.

Your testers are users too, so UX is important. :wink:

Inspect and Reset Preferences

Last year, Woolworths have completely removed single-use plastic bags from all stores nationwide. To help with the transition to reusable bags, we built a feature into the app that allows users to enable bag reminders for their chosen store. We also included a “nudge” feature to assist with discovery – the app would nudge you three times to set up your reminders, after which it assumes you do not want to set it up.

This is one of the many use cases where we leveraged SharedPreferences. This whole feature is based on geofencing around a store, which can be a little finicky. We decided to include a SharedPreference inspector so that we can easily answer questions from our testers like “I did not get any set up notifications, I’m pretty sure I have only gotten two?”.

Being able to see what current values have been saved in the app allows us to quickly triage issues in the wild.


Remember that override Firebase kill switch?

I have already written about resetting SharedPreferences here, and the “inspect” bit follows the same principle as that. Mainly:

This function assumes that the SharedPreferences files your app owns follow this naming convention: MY.APPLICATION.ID_my_preference_file.

But we do need some modifications to the gist quoted in that post. For one, we can extract out the bit that reads the files:

We need to do a bit of processing because we want to have readable names (again, UX!) as well as the name that Android would need to retrieve the SharedPreference. As an example:

File location /data/user/0/com.woolworths.debug/shared_prefs/com.woolworths.debug_prefs.xml
Android-readable name com.woolworths.debug_prefs
Nice name debug_prefs

To keep things simple, we only display a dialog with all the existing values in the SharedPreference:

This option has helped us a lot debugging our nudges out in the wild. It eliminated the need to be connected to a computer, or to fiddle with file viewers, etc.

Show Device Info

Sometimes we want the UI to change based on some device qualifications like say the smallest available width. Using the emulator makes it super easy for us to test these visual breakpoints. But for someone who does not have access to the emulator, it can be quite hard to verify the UI changes we expect.

This screen shows some basic information that might affect how our app displays something to the user:


Minimum information to debug device-dependent UI

Everything under the “Build Information” header is retrieved from Android’s Build.VERSION API or the BuildConfig. And for the “Device Information” section, we utilised windowManager.defaultDisplay.getMetrics(DisplayMetrics()).

The “Account Information” section contains some basic information about the user that might affect the UI. For example, if “Is legal adult” is false, the user will not be able to see any liquor products in the app.

Show Diagnostic Info

There is a lot more information that affects a user’s experience with the Woolworths app other than if they are logged in or not. Inventory is different store-to-store, Rewards and offers may be targetted, legal requirements are different based on the state, among other things.

All of these things may affect the app one way or another, and we use a Diagnostics screen to display all those information.

And with that we wrap up this post on our developer options for UI-affecting variables. In the next post, we will talk about logging, Toasts, and more fun stuff! :confetti_ball: