From a Leaf3 Tool to a Boox Tool

The Leaf3 Cleaner was written for exactly one device. The package list was hard-coded. The documentation said "Boox Leaf3" at the top. The settings I tuned were the ones I had tested on my own unit. It was the opposite of generalizable software, and I was fine with that, because I only owned one Boox device.

Then I plugged in a Palma 2 Pro and ran pm list packages, and the list did not match.

What changed

The core Boox packages were still there. The Google services satellites were still there. The bulk of the list was identical between the two devices. But the Palma 2 Pro is Boox's phone-sized reader, and Boox's cautious response to "phone-sized" was to ship it with a full phone-shaped software stack that nobody actually uses on it.

From the Palma 2 Pro's package list, here is what I had never seen on my Leaf3:

  • A stock Notes app
  • A Dialer
  • A Contacts book
  • A Messaging (SMS/MMS) app
  • A SIM Toolkit
  • A Touchscreen calibration utility
  • SnapCam - the camera app for the rear-facing sensor on a reader
  • Google Books
  • Google Text-to-Speech
  • A stock Sound Picker
  • An Emergency Information app
  • A separate Storage Manager

Twelve extra packages. Every one of them is something you'd expect on a budget Android phone, and none of them has any business running on a device whose entire purpose is to show black text on a gray background. The dialer is particularly funny: the Palma 2 Pro cannot make phone calls. It has no cellular radio. The dialer sits there, bound to nothing, waiting for a call that cannot come.

The refactor

I could have forked the Leaf3 Cleaner, called the new one "Palma 2 Pro Cleaner", duplicated the shared packages, and added the twelve new ones. That is what the first draft of my brain wanted to do. It would have been fifteen minutes of work.

I didn't, because I knew what came next. Another Boox device eventually. Another slightly different package list. Another fork. Within a year I would have three or four near-identical codebases drifting apart from each other every time I added a feature. I had seen that movie before in other projects.

So I restructured the tool instead. The package list became two sets:

  1. A common set - packages that live on every Boox device I have touched, safe to remove without reference to model.
  2. A per-model set - packages specific to a particular device, like the Palma 2 Pro's twelve phone-shaped extras.

On launch, the tool asks ADB what model it is connected to, loads the common list, appends the matching per-model list, and filters both against pm list packages so only packages that are actually present become checkboxes. If you connect a device the tool has never seen, you still get the common list and nothing breaks. Adding support for a new model is appending a dictionary entry.

The Service disable and Performance tuning tabs were already general, so they didn't need to change. The refactor was entirely in how the app-removal list was composed.

Now it's Boox Cleaner

I renamed the tool. The documentation no longer mentions a specific model in the title - it mentions model coverage in a table further down, which is where that kind of information belongs. The build pipeline (single Windows executable, ADB bundled, no installation) stayed the same. The user-facing surface area didn't change. Someone coming from the old version would not notice anything had happened except that the Palma 2 Pro now showed up in the app-removal list.

The interesting part, for me, wasn't the code. It was the realization that a "universal" tool for Boox is mostly a tool that knows how to describe the differences between models. The common ground is large. The deltas are small. Treating the deltas as data rather than code is the entire trick.

You can find the tool and the full setup instructions - including the Activity Launcher step - at apps.txid.uk/en/boox-cleaner/. It's a standalone Windows executable. USB cable, one window, three tabs, a checkbox list, and a device that finally stops fighting you.