DebugDrawer

A configurable debug drawer to use in your Android app. Inspired by u2020.

The debug drawer is something you can add to your debug builds to make your life easier as a developer or tester. It provides a convenient way of exposing development specific controls without cluttering up your user interface. There are quite a few possibilities this opens up, such as adding shortcuts, displaying diagnostic information, or anything you might want.

To give you some inspiration, this repository provides out of the box modules for:

  • Configuring Retrofit endpoints and mock network behaviour
  • Displaying device information
  • Viewing and sharing Logcat entries collected by Timber
  • Providing a more convenient entry into LeakCanary
  • Selecting a logging level and piping OkHttp logs into Timber

Of course, you're free to implement your own modules as well.

DebugDrawer

Usage

This library assumes that for a given Activity you will populate one to many ViewGroups inside
of it over its lifetime. Instead of calling setContentView() directly, define a function in both
your debug and release builds to get the root ViewGroup that Activity should use to present a
screen. This would look something like...

Debug

fun getRootContainerFor(activity: Activity): ViewGroup {
  return DebugDrawer.with(activity)
      .addSectionTitle("Device information")
      .addModule(DeviceInfoModule())
      // ...and whatever other modules you want to add.
      .buildMainContainer()
}

Release

fun getRootContainerFor(activity: Activity): ViewGroup {
  return activity.findViewById(android.R.id.content) as ViewGroup
}

You can then use this ViewGroup to populate your Activity's view, or use it as the container
when push/popping Fragments or Controllers or whatever you fancy. For your debug builds this
container will be inside of a
DrawerLayout,
allowing you to swipe from the "end" edge of your screen to get access to debug settings. For
release builds you'll be pushing views into the root container as normal.

Making new modules

You have two options if you want to add custom modules to your drawer. You can implement
DebugDrawerModule,
or you can extend
KeyValueDebugDrawerModule.
The latter is useful if all you want to do is display some key value pairs. The former allows you to
return whatever View you want. It also provides optional lifecycle callbacks if your module needs
to bind and unbind to expensive resources.

The debugdrawer dependency has a few publicly exported style resources. You can use these styles
(such as Widget.DebugDrawer.RowTitle) to ensure your custom module maintains a consistent
appearance with other modules in the drawer. Yes, this is a development tool, but developers can
appreciate nice UIs too!

Why another implementation?

It's true; there are a few other implementations of a reusable debug drawer out there. This project
aims to have a simpler API, especially when it comes to creating custom modules. Also having the
library written in Kotlin makes it more enjoyable to work on ?.

Sample apps

screenshot_sample

This repository provides two sample apps that demonstrate usage of the debug drawer. The
simple-sample-app has no other dependencies and is about as bare-bones as you can get. The
sample-app is a bit more complex. It interfaces with the
Giant Bomb API to retrieve and display a list of video games, and
aims to be closer to a real application.

Browsing through the implementation of sample-app should provide you with an idea of how you could
add the debug drawer to your app. You might want to use dependency injection to assist in setting it
up, or you could follow the example and try and roll something by hand. Whatever your choice, it
doesn't need to be particularly complex.

Provided modules

LeakCanary

LeakCanary is a fantastic tool for detecting memory leaks in your app. The only problem with it is
how it adds a launcher icon for each app you have installed that uses it. This module takes care of
removing that launcher icon and cages LeakCanary in the debug drawer.

The only requirement for using this module is that you're calling

override fun onCreate() {
  LeakCanary.install(this)
}

in your Application class as per LeakCanary's documentation.

Timber

Timber provides some nice utility on top of Android's standard Log class. This modules aims to
enhance it further by providing a mechanism to view logs from within your own app. In addition, it
allows you to share the current collection of logs if you happen to see something interesting.

To use this module you must call

override fun onCreate() {
  LumberYard.install(this)
}

inside of your Application class. Because it would be annoying to define two separate
Application classes for both debug and release builds, a debugdrawer-timber-no-op dependency is
provided. This allows you to keep the LumberYard.install(this) call in your Application for
release builds.

OkHttp logger

It can be incredibly useful to view HTTP requests and results when debugging your app. This module
provides a dropdown menu in the drawer to select what level of logging you'd like to see for your
HTTP requests. It relies on you using OkHttp as your HTTP client, and pipes its output into Timber.

To use it, first add
HttpLogger.interceptor
as an interceptor to your OkHttpClient. Then pass HttpLogger on to
OkHttpLoggerModule.

Device info

Nothing too fancy, this module displays

  • Manufacturer
  • Model
  • Screen resolution
  • Screen density
  • Current API version

Retrofit

This is one of the more complicated modules. Retrofit is a great tool for abstracting RESTful APIs,
and often you might want to configure its behaviour. This is useful if you make use of
retrofit-mock and want to modify
NetworkBehavior at runtime, or maybe your debug app can target one of many different environments,
such as development, staging, or production.

To begin, you must create a list of
Endpoints.
This list might include entries such as staging, or mock.

Next, create an instance of
DebugRetrofitConfig.
This class takes care of persisting settings between app launches, and forwarding any runtime
modifications to NetworkBehavior. It also ensures that when you select a new Endpoint your
entire app process is restarted.

Finally, you can add
RetrofitModule
to your debug drawer builder and it will take care of the rest. It might be easier to understand by
looking at an example, so check out sample-app to see it in action.

Download

All artifacts are up on jcenter.

For the main library

au.com.gridstone.debugdrawer:debugdrawer:0.9.1

For the LeakCanary module

au.com.gridstone.debugdrawer:debugdrawer-leakcanary:0.9.1

For the Retrofit module

au.com.gridstone.debugdrawer:debugdrawer-retrofit:0.9.1

For the Timber module

au.com.gridstone.debugdrawer:debugdrawer-timber:0.9.1

For the no-op Timber module

au.com.gridstone.debugdrawer:debugdrawer-timber-no-op:0.9.1

For the OkHttp logger

au.com.gridstone.debugdrawer:debugdrawer-okhttp-logger:0.9.1

GitHub