Customizing Android’s SystemUI

May 18, 2022

Last month I wrote a bit about my work on porting Android 12 to the PineNote, an open source E-Ink tablet. Since then I’ve gotten Android booting and running pretty well, but as anyone that has used an e-reader knows, things that look good on a normal display tend to look pretty bad on a monochrome display with a low refresh rate. To solve this problem, I’ve been researching how to customize and extend the default SystemUI to make it look and feel better on EInk devices.

To figure out what I need to do, I took a look at both the default SystemUI and CarSystemUI, an extension made specifically for Android Automotive. The first thing I noticed was that the different services that make up SystemUI are written as Dagger (a dependency injection framework) modules,  so any of them can be replaced as long as the replacement has the same interface as the original. The second thing I noticed is that each of the modules are loaded by the SystemUIFactory component, which can be explicitly set through a resource variable. Knowing this, and having CarSystemUI as a reference implementation, I got to work creating my own version. First, I created a new SystemUIFactory that loads the default SystemUI modules, with two resource variables to list what modules should also be included and any that should be explicitly excluded. 

After this, I thought it was time to start customizing. Nope. Turns out, a good chunk of SystemUI is contained within the status bar module, which has its own dagger setup for injecting modules. I think this is a holdover from when android devices had dedicated navigation buttons, and the only real UI part was the status bar, but there may be some greater architectural reason for it. So next, I wrote some more boilerplate code for injecting modules into the status bar. I compiled the app, loaded it to my device and, surprisingly for a first attempt, it worked! Everything looked and behaved the same as before, but at the time it felt like a real accomplishment.

Now that I had a way to easily change SystemUI, I started by removing a handful of default components. I removed the Picture in Picture module, since videos and other content that PiP is used for isn’t relevant for EInk devices. I also removed biometrics support, since EInk devices are generally quite basic and don’t have any biometrics hardware. ScreenDecorations were the next thing to go. EInk displays are very low power, so in that vein I felt removing GPU-expensive UI elements (all handled by the ScreenDecorations module) was fitting. Some other things were removed as well, but you get the gist of it.

After compiling and installing the app, I noticed two things. The first was that the UI felt much more responsive than before, which I attribute to the exclusion of ScreenDecorations. I also noticed that the APK was only 6.5Mb. I compared this to the SystemUI on my phone, which was 23Mb. While size shouldn’t really impact performance that much, it was a minor assurance that all the modules I excluded got removed as dead code. 

That’s where I left off, but as with all of my work on the PineNote it is still ongoing. Next, I’d like to move the navigation bar to the left so that it’s more accessible when the device is held. You can take a look at the code and  any progress I’ve made on my GitHub repo. And, as with any open source project, feel free to contribute!