The Day Rolled Over and Yesterday's Wallpaper Came Back — Designing Date Boundaries Instead of Trusting an Agent's Time Code
A record of redesigning a daily-rotating wallpaper feature that showed yesterday's pick after midnight for some users and switched twice in one night for travelers. I separate the device clock, time zone, and daylight saving time into three distinct failure sources, show how to define a stable day key, defend reward boundaries against a rewound clock, and test it all with an injectable clock — from a solo indie developer's point of view.
Every Favorite Tap Was Redrawing Every Visible Wallpaper — Stopping Needless Recomposition in Compose, Measured
A record of fixing a wallpaper grid where toggling a single favorite recomposed every visible thumbnail. Covers turning on Composition Tracing to measure first, tracking the unstable parameter down, stabilizing the data model, handling lambdas and derived state, and comparing recomposition counts before and after from an indie developer's view.
The Day Generation, Device, and Internal-Test Shipping Became One Step — What I Refused to Hand Over
AI Studio now turns a text prompt into a Kotlin/Compose app and carries it through the emulator, a real device, and Google Play's internal test track from one screen. Behind that convenience sits a question: how much of the moment of shipping do you hand to the machine, and what do you keep in your own hands? Here is where I draw the line as a solo developer running several apps, and the implementation that holds that boundary.
Three Paths Were Each Picking Their Own Number — Deriving versionCode From a Single Source So Releases Stop Stalling
Now that AI Studio can generate an app from one prompt and push it straight to Play's internal testing track, three paths — you, CI, and the agent — each allocate versionCode on their own and collide. Here's how to derive the number from a single source and add a pre-upload guard, with working code.
The Review Prompt Fired but Nothing Appeared — Designing Around Play In-App Review's Quota and No-Show Guarantee
Play In-App Review's launchReviewFlow can succeed without ever showing a dialog. This walks through the three traps — quota, no display guarantee, and silent testing — and the engagement-based trigger design that fires at the right moment without colliding with ads, with steps to have Antigravity implement it.
Only Slow Right After Install — Cutting Android Cold-Start Time with Baseline Profiles, Measured
Why an Android app stutters on launch only right after install or update, explained through JIT and Cloud Profiles, plus a measured walkthrough of cutting cold-start time with Baseline Profiles — from building a Macrobenchmark harness to staged rollout, from an indie developer's perspective.
It Only Crashes in Release — Tracking Down When R8 Full Mode Broke My Gson Mapping
It works in debug but crashes only in release. This walks through the R8 full-mode pattern that breaks Gson reflection, how to reproduce it locally, deobfuscate the stack trace, and write the smallest keep rules that fix it.
Letting Users Switch the App's Language Without Touching Their Device Language — Notes on Android Per-App Language
How to implement in-app language switching on Android with AppCompatDelegate.setApplicationLocales and locales_config, plus the gotchas around pre-API-33 compatibility, activity recreation, and AdMob, from an implementation point of view.
Porting a Wallpaper Viewer's Slideshow and Page-Scrubber from iOS to Android — Where the Two-Way Sync with SnapHelper Tripped Me Up
A hands-on record of porting a full-screen wallpaper viewer's slideshow and bottom scrubber from iOS to Android. How I pinned down the current page with RecyclerView and SnapHelper, synced it two-way with the scrubber, and resolved the conflict between auto-advance and user input with a small state machine — in working Kotlin.
The Back Button Showed an Interstitial Sometimes, Not Others — Rewriting Nested ifs Into a List of Independent Guards
Interstitial display on back press was unstable because nested if statements hid the priority between conditions. Here is how I split it into reason-returning guards and generated tests from a decision table.
A Few Low-Density Phones Lost Their Bundled Wallpaper — The drawable vs nodpi Boundary in Play's Density Splits
App Bundle density splits will happily split images that should never be split, dropping a static resource on one density bucket only. Here is how I reproduced it with bundletool and fixed it by moving to drawable-nodpi or disabling density split — with the decision criteria.
Vetting AI Studio's Native Android Code Before It Reaches Your Live App
AI Studio's native Android vibe coding produces working screens at startling speed. But before it goes into a live app, it needs its own vetting. Here is a pre-merge review design for generated Kotlin.