I Built My Own Android Car Launcher
The head unit in my Grand i10 came with a home screen nobody had tested in a moving car, so I wrote a replacement. 2.1 MB, zero dependencies, a drive mode that triggers at 30 km/h. Then I ran it on the actual panel and found three crashes in the first five minutes, one of them invisible because a crashed launcher looks exactly like a working one.
The head unit in my Grand i10 is aftermarket. A myTVS panel, Android 11, a Rockchip chip from 2017 and just under 2 GB of RAM. It does the job. What it came with was a home screen built by someone who had clearly never sat in a moving car: tiny icons in a grid, a wallpaper of a sports car the Grand i10 is not, and a clock that was somehow the smallest thing on the display.
I debloated it first. Turned off 16 packages, won back some memory, and then realised memory was never the problem. The problem was that I had to look at that screen at every red light.
So I wrote my own. It is called Dash.
What it actually is
2.1 MB, zero third-party libraries. No AppCompat, no Material, no Compose, just framework APIs. That is partly taste and partly the hardware, because four A35 cores at 1.5 GHz do not forgive a dependency tree.
The screen is true black, because at night anything else becomes a light source sitting in your peripheral vision for the whole drive. Each tile is a vivid squircle that the app icon fills edge to edge, rather than a small glyph floating inside a grey container. Material fills, no borders. The only colour on screen that does not belong to an app is the speed readout, which is amber, for roughly the same reason instrument clusters have been amber for fifty years.
Then the two features I actually wanted.
Drive mode. Above 30 km/h the layout collapses to four large tiles and the speed becomes the biggest thing on the display. It goes back to normal below 18. Two thresholds and not one, because with a single threshold the interface flickers every time you crawl through traffic, and that is worse than either layout on its own.
Trip stats. This one I got wrong first. I built it around ignition cycles, which is the obvious way to do it, and then asked myself what happens on a Bhubaneswar to Bargarh run. That is one drive, about 330 km, with a tea stop and a lunch in it. The ignition version would have filed that as four separate trips. So a trip is now a journey. It survives stops and closes itself after three hours parked. Average speed is computed over moving time rather than elapsed time, otherwise every long drive averages out to “including lunch”.
The part worth writing down
All of that compiled cleanly and looked perfect on my laptop. Then I sat in the car at seven in the morning and ran it on the actual panel.
Three crashes in the first five minutes.
Two of them were the same root cause in two different files. I was hiding the system bars before calling setContentView. There is no DecorView at that point, and the framework throws rather than returning null, so the safe-call operator I had carefully written never got a chance to save me. The setup wizard and the icon pack picker, which were the two headline features of that release, were both dead on arrival.
And I could not see it. The setup wizard died inside onCreate and left the home screen showing, which is exactly what a working launcher looks like. It read as “setup got skipped this time”, not “setup crashed”. Same story with the button that re-detects installed apps. That looked like a dead button rather than a crash.
A launcher is the only thing I have written that hides its own failures behind itself. Everything else at least gives you a blank screen, or a toast, or a force-close dialog you can screenshot.
I found the second one by grepping the call order across all six activities rather than by hitting it. Four of them inflate an XML layout and happen to get the ordering right by accident. The two that build their views in code got it backwards.
The third crash was the wallpaper picker. This firmware ships no DocumentsUI at all, so the Storage Access Framework is simply absent and OPEN_DOCUMENT resolves to nothing. Switched it to GET_CONTENT, which both the gallery and the vendor file manager answer.
Still open
Drive mode and trip stats have zero runs between them. Both need real motion, so they are riding along on the next long drive. My guess is the trip resuming after a long engine-off stop is the piece most likely to be wrong, because it is the only state that has to survive the unit powering down completely.
The code is public at github.com/debashisn94/dash-car-launcher. The build currently attached to the release still has those three crashes in it, so give me a day before you flash anything.