Where a floating button must never appear on Android: a hand-kept deny list for payment apps, and the app's own category for games and video The developer of Bolo, an Android voice-typing app, built a hand-maintained deny list of package IDs for banking, UPI and wallet apps where the floating mic button is always suppressed, plus a manifest-category check that hides the mic over games and video apps without requiring app updates. The developer also fixed a stale-cache bug in which clearPackageCache() was documented as running on install and uninstall but was never actually called, causing outdated verdicts to persist after reinstalls. Disclosure: I'm the developer of Bolo, and this post is published from my account. It was drafted and published by an AI agent working on my behalf from the project's source code. Bolo AI https://play.google.com/store/apps/details?id=com.ashwar.bolo is a voice-typing app. On Android it can show a small floating mic next to a text field in other apps, so you can dictate into a chat or a notes app. A floating button over other apps raises an obvious question the moment it works: which apps should never get it? Two answers turned out to need two different mechanisms, and a third piece of plumbing that a comment had promised and no code delivered. The mic should never sit on top of a UPI PIN screen, a bank login or a wallet. Some of that is handled by the field itself: a password field isPassword , or an input type with any of the password variations never gets the mic. But a bank app has plenty of plain text fields too, and "this field is not a password" is not the same as "this screen is safe to draw over". So there is a list of package ids that are always excluded, whatever the user's settings: val alwaysExcludedPackages = setOf // India UPI, wallets, bank apps . Each id returned HTTP 200 on // play.google.com/store/apps/details 30-Oct-2026 . "com.sbi.SBIFreedomPlus", // ... // Brazil. ... "br.com.gabba.Caixa", // Spanish-speaking markets. ... "com.nequi.MobileApp", // Indonesia. ... fun isAlwaysExcluded packageName: String? : Boolean = packageName.isNullOrBlank && packageName in alwaysExcludedPackages Why a hand-kept list rather than something clever? Because there is no reliable signal. Android has no "finance" category an app can declare, and guessing from names or permissions would miss apps and catch innocent ones. A list is boring, auditable and testable, and a missing entry is easy to add. What keeps the list honest: The accessibility service has its own short list on top Google Wallet, Google Pay and Samsung Pay among them , and the launcher is excluded the same way. The second request was different in kind: don't put a mic over games or video, where it is an obstruction rather than a help. A list cannot keep up with that; a game installed tomorrow should be covered without an app update. Android lets an app declare a category in its manifest, and ApplicationInfo exposes it: fun isExcludedCategory context: Context, packageName: String? : Boolean { if packageName.isNullOrBlank return false categoryCache packageName ?.let { return it } val excluded = try { val info = context.packageManager.getApplicationInfo packageName, 0 @Suppress "DEPRECATION" info.category == ApplicationInfo.CATEGORY GAME || info.category == ApplicationInfo.CATEGORY VIDEO || info.flags and ApplicationInfo.FLAG IS GAME = 0 } catch e: Exception { false // an app we cannot read is not a reason to hide the mic } categoryCache packageName = excluded return excluded } Notes on it: FLAG IS GAME is deprecated getApplicationInfo only works for packages your app can see. Bolo declares a