XLauncherIcons
Sample App: Changing Launcher Icon Programmatically
Install / Use
npx skills add ryanw-mobile/XLauncherIconsInstalls into whichever agent you are using.
Amazon Q Rules
Amazon Q Developer rules
Quality Score
Category
Development & EngineeringSupported Platforms
Skill content
View source on GitHubXLauncherIcons Project Rules
This file defines the authoritative coding standards and intentional design decisions for this project. These are not suggestions — they are the established patterns all code in this project follows. Do not raise findings that conflict with these standards.
Project Context
XLauncherIcons is a sample/demonstration Android app. It is not a production service. Defensive coding patterns appropriate for public APIs or production systems are intentionally omitted where they would add noise without value.
IconManager: Internal API with Closed Input Set
IconManager.setIcon(componentName: String) and IconManager.getActiveIconComponent() are internal methods. All componentName values are sourced exclusively from the gregAppIcons compile-time constant list. No external caller can supply arbitrary strings.
- No validation of
componentNameagainstgregAppIconsis required or desired. The architecture enforces correctness — adding a runtime guard implies external callers exist, which they do not. - No try-catch is required around
setComponentEnabledSettingorgetComponentEnabledSetting. All components are declared inAndroidManifest.xmlat compile time (eliminatingIllegalArgumentException). The app only modifies its own activity-aliases (eliminatingSecurityException). These exceptions have no reproduction path. - The
?: gregAppIcons.firstOrNull()?.componentfallback ingetActiveIconComponent()is intentional. On fresh install, no alias is explicitly enabled — the system uses the first declared activity-alias. The fallback matches that system behaviour and prevents the UI from showing no selection.
MainViewModel: Optimistic UI Pattern
MainViewModel.setIcon() updates _activeIconComponent immediately after calling iconManager.setIcon(), without waiting for verification.
- This is the intentional optimistic UI pattern, chosen for responsiveness.
setComponentEnabledSettingis deterministic for statically-declared components. There is no failure path to guard against.- No try-catch, no post-call
refreshActiveIcon(), and no state rollback logic is required. - Re-querying state immediately after
setComponentEnabledSettingis also unreliable — the system may not have propagated the change yet, making optimistic update the correct approach.
MainViewModel: viewModelScope.launch for setIcon()
MainViewModel.setIcon() uses viewModelScope.launch even though iconManager.setIcon() is synchronous.
- This is intentional.
viewModelScope.launchprovides lifecycle-aware cancellation and structured concurrency. It is the idiomatic ViewModel pattern for all state-mutating operations. - The IPC overhead of a single
setComponentEnabledSettingcall is negligible.Dispatchers.IOis not needed. - Do not suggest removing the coroutine wrapper or adding
withContext(Dispatchers.IO).
MainActivity: IconManager and ViewModel Instantiation
IconManager is instantiated as remember { IconManager(this) } inside setContent. MainViewModel is obtained via viewModel(factory = ...).
remember { }prevents recreation on recomposition. This is correct and intentional.viewModel()fromlifecycle-viewmodel-composepreserves the ViewModel across recompositions and configuration changes.- The
Contextinsideremember { IconManager(this) }does not become stale —rememberis scoped to the composition, which is destroyed with the Activity. There is no lifecycle mismatch. import androidx.compose.runtime.rememberis already present inMainActivity.kt.- Do not suggest moving instantiation to
onCreate(), usingby lazy, usingby viewModels(), or any alternative. The current pattern is correct.
setComponentEnabledSetting Loop Performance
IconManager.setIcon() iterates over gregAppIcons and calls setComponentEnabledSetting for each entry.
- The list size is fixed and small (defined at compile time). This loop cannot cause ANR or perceptible UI freeze.
- Do not flag this as a performance or threading concern.
Unit Tests: MainViewModelTest
- The
init should refresh active icontest stubsgetActiveIconComponent()explicitly before constructing the ViewModel. The relaxed mock default is never reached. NotestDispatcher.scheduler.advanceUntilIdle()is needed —refreshActiveIcon()ininitis a direct synchronous assignment, not a coroutine. - The
setIcon should call iconManager and update statetest already callstestDispatcher.scheduler.advanceUntilIdle()and verifies both theiconManager.setIcon()call and the resulting state. The test coverage is complete and correct as written. - Do not suggest modifications to these tests.
Related Skills
Agent-Reach
84.4kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
73.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
career-ops
72.4kOpen-source AI job search: scan job portals, evaluate listings into a structured A-H report with a global 1-5 score, tailor your CV, track applications — runs locally in your AI coding CLI (Claude Code, Codex, OpenCode, Antigravity…)
ai-job-search
43.6kThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.
Security Score
Audited on Invalid Date
