Said another way, how to supercharge your development workflow with a debug drawer.
As Android developers, we're constantly looking for ways to streamline our workflow.
One often-overlooked tool that can significantly boost your development process is the debug drawer.
In this post, we'll explore how to implement and leverage debug drawers to take your Android app development to the next level.
What is a Debug Drawer?
A debug drawer is a hidden panel in your app that contains various tools and information useful during development and testing.
Think of it as a Swiss Army knife for developers – always there when you need it, but invisible to regular users.
Adding A Debug Drawer To Your App
The concept we are going to employ to add a debug drawer to your app is to use debug and release configurations in Gradle to include different modules depending on the build.
To add a debug drawer to your app, we will first start by creating a new module.
In this example, I'll call it :debug-drawer
We are also going to want to create a no-op release implementation of this module so we can have different behaviors in debug vs. release builds.
In this example, I'll call it :debug-drawer-release
Lastly, we are going to create a :debug-drawer-api
module for common configurations of our debug drawer feature.
In our :app
module, I'm going to add :debug-drawer
to the :app
module as a dependency via the debugImplementation
Gradle configuration.
I'm also going to add the :debug-drawer-release
to the :app
module as a dependency via the releaseImplementation
Gradle configuration.
Lastly, I'm going to add :debug-drawer-api
to the :app
module as a dependency via the regular implementation
Gradle configuration
Now comes the actual implementation of opening the debug drawer!
In this example, we will be opening the debug drawer by pressing the volume down key two times.
The main reason for this is most developers on our team use emulators, where sliding to open can be awkward.
Add the following code to the :debug-drawer-api
module:
interface DebugOnlyKeyListener {
fun onKeyDown(event: KeyEvent)
}
Then, we will modify the :debug-drawer
and :debug-drawer-release
modules to both depend on the :debug-drawer-api
module via the implementation
Gradle configuration.
Now, we can move on to actually creating debug and release implementations of DebugOnlyKeyListener
We will create classes with the same name that implement the DebugOnlyKeyListener
.
The one that lives under :debug-drawer-release
will have a no-op implementation, while the one that lives under :debug-drawer
will have an actual implementation.
Now, let's create the actual implementation for DebugOnlyKeyListener
in the :debug-drawer
module!
import android.app.Application
import android.view.KeyEvent
import com.example.debugdrawer.debug.drawer.api.DebugOnlyKeyListener
class DebugOnlyKeyListenerImpl(val application: Application) : DebugOnlyKeyListener {
private var count = 0
override fun onKeyDown(event: KeyEvent) {
if (event.isVolumeDownPressed()) {
count++
} else {
count = 0
}
// Look for volume down twice in a row.
if (count >= 2) {
count = 0
// start the debug activity
val intent = Intent(application, DebugDrawerActivity::class.java)
intent.flags += Intent.FLAG_ACTIVITY_NEW_TASK
application.startActivity(intent)
}
}
private fun KeyEvent.isVolumeDownPressed(): Boolean {
return keyCode == KeyEvent.KEYCODE_VOLUME_DOWN &&
(action == KeyEvent.ACTION_DOWN || action == KeyEvent.ACTION_UP)
}
}
While a fairly trivial implementation, we are just listening for 2 consecutive volume down presses to trigger some functionality.
Now, we can add an Activity to the :debug-drawer
module.
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
class DebugDrawerActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text("Hello from debug drawer!")
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name=".DebugDrawerActivity"
android:launchMode="singleInstance" />
</application>
</manifest>
Lastly, this can all be tied together in the main Activity that you want to trigger the debug drawer from.
Now, to test a debug build!
The debug Activity correctly opens in a debug build!
Now to test a release build.
In a release build, nothing happens after pressing the volume down two times.
At this point, you can add any functionality you want to your DebugDrawerActivity
like listing feature flags, modifying and viewing network requests, etc.