The Soosu Studio Blog is an English resource for Android users who want clear explanations of our apps. Each article focuses on one useful workflow: what the app does, when it helps, and how to get started.
A clock on the cover screen, a soft glow from the inner display. How we brought an iPhone Duo StandBy-inspired idea to supported Android foldables, and why the light does not stay on continuously by default.
A wave of missed-alarm reports traced back to a permission Android 14 stopped granting by default. Here is what we found, the diagnostics we built afterwards, and why we now refuse to call a rule an alarm unless we can prove it is one.
Scan history is easy to build and hard to bound. Which payloads never reach it, how repeated scans of the same label collapse, and why the result screen became a proper step rather than a thing that flashes past.
A garment is referenced by every outfit that used it, so removing one row quietly removes history that has nothing to do with it. What we changed about deletion, and what outfit history is actually good for.
Android 13 made notifications a runtime permission, and a timer app whose entire output is a notification found out the hard way. Plus the stopwatch mode we added for work that does not fit a preset.
An accessibility service can be disabled by the system, by an update, or by a settings review, and there is no callback for it. Detecting that, plus variables, selected-text replacement, and backing up a library full of personal details.
Redaction tools have a specific failure mode - the hidden data is still in the file. Two well-known Android bugs made that concrete, and they shaped how ONEShot's blur is applied, flattened, and written to disk.
Rebuilding the interface in Compose forced us to look at the alert code, where a single vague notion of an alert had been quietly doing three unrelated jobs badly. Plus what Android 14 foreground service types meant for alighting reminders.
Adding a markdown toolbar to a text editor means writing into a field while an input method is mid-composition, which is a good way to duplicate or drop characters. Plus what we do when the same entry is edited offline on two devices.
The editor preview and the full-screen banner were two separate pieces of rendering code, which meant they disagreed - and the one you checked was not the one your audience saw. Plus what sharing a message as a link actually involves.
On-device text recognition ships as separate models per script, so a receipt with a Korean address and an English product name has no single right recognizer. What we do instead, and the rotation bug that made everything look broken first.
A pass is a signed zip archive with a JSON manifest, a set of images at several densities, and a barcode field with an encoding declaration that catches everybody. A walk through the format and what we can and cannot honour on Android.
Widget configuration is stored per widget id, and a single shared preference key is the bug that produces a home screen where every widget shows the same city. Plus why a widget cannot refresh whenever it likes.
Sync bugs are rarely about the network. Ours were about deletes that had nothing to represent them, a list that flashed empty during login, and photos that synced on a completely different schedule from the records they belonged to.
Making a wallet app appear in the Open with list for a pass file sounds like one intent filter. It is closer to six, because file managers, browsers, and mail clients each describe the same file differently and some of them describe it as nothing at all.
Adding a timer and a stopwatch to a clock app turned out to be a lesson in Android's three different clocks, and in what happens to each of them when the device sleeps, reboots, or has its time corrected mid-measurement.
A camera scanner is a frame pipeline, and the two ways it commonly breaks are forgetting to release a frame and firing on every frame that decodes. One stops the app dead, the other buries the user in results.
A bug report about blank saved notifications led us through Android notification extras, CharSequence versus String, and four different notification styles that each store their body text somewhere else.
Android's accessibility action for setting text replaces the entire field. Expanding a trigger means reading the whole thing, rebuilding it, writing it back, and restoring the cursor - and every one of those steps can fail in a different app.
A subscription tracker is arithmetic on amounts and dates, and both have a standard way to go wrong. Rounding that does not add up, an annual plan that is not a twelfth of itself each month, and a renewal date in somebody else's timezone.
A wallet app is a small database of things people would rather not lose or leak. What we store, what we deliberately do not, which Android backup paths would have carried it off the device, and how to keep the list honest.
Updating a display once a second sounds like a timer loop. It is not, and the difference shows up as digits that change a fraction late, drift over hours, and a clock that is wrong for a whole minute after a timezone change.
A countdown has more states than it looks like, and the interesting bugs all live in the transitions. What a pause means when the process dies, what counts as a completed session, and why we made abandoning one explicit.
Moving text across a screen by a fixed number of pixels per frame works perfectly until someone opens it on a 120 Hz display. What variable refresh rates do to animation, and how to make a banner readable at the back of a room.
Automatic page detection is a contour-finding problem, and contour finding needs contrast. A walk through how DocScanner decides where a page ends, why it gets it wrong, and the capture routine that stops it mattering.
Notification matching looks like string comparison until you meet re-posted notifications, Unicode normalisation in Korean text, and apps that move their content into a field your rule never reads.
Building a notification filter on Android means working inside NotificationListenerService, where the only real verbs are cancel and snooze - and where group summaries, ongoing flags, and listener rebinds decide whether your app looks reliable.
The hardest problem in a bus app is not arrival times, it is telling two nearly identical stops apart. What we changed in search ranking, favourites, and the transfer flow after reading a year of support mail.
Showing a barcode means turning the display up, and turning the display up means being responsible for turning it back down. A small feature with a surprising number of ways to leave someone's phone in a state they did not choose.
An always-on clock is an app that deliberately displays the same bright pixels in the same place for hours. On OLED that has consequences, and designing around them changed almost every visual decision in the app.
Almost every field on an appliance record is something the user might not know when they create it. Requiring any of them produces either empty records or invented data, and we shipped both before working out which mistake we had made.
Unlimited notification history looked like a feature until the databases got big, the list started stuttering, and one-time passcodes were still sitting in storage six months later. Here is what we changed and the retention model we landed on.
Android has a built-in PDF writer, and using it the obvious way produces files nobody can email. What we learned about image compression inside PDFs, bitmap memory, and why a scanner app is mostly a memory management problem.
Keeping a bitmap per undo step is the first thing you write and the fastest way to crash an image editor on a phone. Storing operations instead changed the memory profile, the export path, and what the app can promise about quality.
Deciding when a sequence of characters is a trigger and not just typing turns out to be the whole problem. Word boundaries, prefixes, undo, and building a phrase library that still sounds like you wrote it.
Attaching an image by reference is the efficient choice and the wrong one. Why old entries lost their photos, what a persistable URI permission does not survive, and where a diary should keep location data.
Autosave is supposed to be the feature that means you never lose anything. Ours briefly did the opposite, for a reason that is embarrassing to write down and worth writing down anyway.
Rendering a barcode is drawing black rectangles, and nearly every way of doing it produces something a scanner cannot read. Fractional pixel widths, anti-aliasing, missing quiet zones, and the theme that inverts your code.
The arrival time on your screen is an estimate derived from a vehicle position that was reported some seconds ago and passed through several systems on its way to you. Here is what BusanBus does with it, and why refreshing faster does not help.
Turning a matched notification into an alarm that actually reaches you means getting past Do Not Disturb, the lock screen, the ringer mode, and on Android 14, a full-screen intent permission that is not granted by default.
Recurring maintenance sounds like adding an interval to a date. Then January 31st plus one month has no obvious answer, a filter change drifts backwards through the calendar, and a reminder fires on the wrong day for anyone who travels.
A scrolling loop that has no visible seam is arithmetic on text width, and measuring text width is harder than it looks once fonts fall back, Korean and Latin mix, and someone types a flag.
Storing a membership number and drawing a barcode from it is not enough. The symbology matters, the check digit matters, and a code that looks right on screen can be a different value to the scanner.
A code is a string, and a string can be a domain that renders identically to one you trust. Why we show the destination instead of opening it, what punycode is doing in your scan results, and which payloads we treat as dangerous.
Handing an image to another app on Android means handing over a content URI and a permission grant, and then having no idea when the other app is finished with it. Cleaning up too early broke sharing in a way that looked like a network error.
Combining every top with every bottom produces thousands of outfits and no useful ones. What we learned about why suggestion features fail in a wardrobe app, and what we built instead.
A focus app spends most of its life in the background, which is the one state Android does not guarantee you. What we changed after realising our timer was storing its state in exactly the place the system is most likely to take away.
Automatic colour detection on clothing photos is mostly a white balance problem, and white balance is decided by the camera before your code sees anything. Why the app asks you to confirm what it worked out.