Roamer
1.0.1 · GitHub
More about this app
Developer tool overriding SIM country ISO and carrier name via Shizuku, with optional per-app locale syncing.
Roamer
Roamer is an Android developer tool for overriding a SIM card's reported home country (ISO) and carrier name without requiring root access. It also allows optionally syncing the overridden region to target applications via per-app locales.
English · 简体中文
Stack: Kotlin · Jetpack Compose · Material 3 · Shizuku · minSdk 31 (Android 12+)
Overview
Roamer modifies the CarrierConfig override layer exposed by Android telephony APIs via Shizuku. This lets developers test how apps respond to different SIM country ISOs and carrier names without swapping physical SIM cards.
Optionally, Roamer can mirror the primary SIM's overridden country code to selected apps using system per-app locales (Android 13+). Restoring the SIM automatically resets selected apps back to their original locales.
Features
- Rootless SIM country ISO and carrier name override via Shizuku.
- Multi-SIM support: apply or restore settings across all active slots.
- Preset configurations for popular target regions (US, JP, KR, CN, HK) and carriers.
- Reversible restore: values are derived dynamically at runtime rather than saved to disk.
- Optional per-app region override for targeted app testing.
- UI details: side-by-side display of original vs. active values, monospace technical codes (MCC/MNC/ISO/subId), and light/dark theme support.
Scope of Overrides
Roamer only edits the CarrierConfig override layer and does not alter underlying SIM or RIL hardware attributes.
| Target Value | Overridable | Telephony API |
|---|---|---|
| Country ISO | Yes | getSimCountryIso |
| Carrier Name | Yes | getSimOperatorName |
| MCC / MNC Digits | No | getSimOperator (SELinux protected) |
| Network Registration | No | getNetworkOperator / getNetworkCountryIso |
Because MNC and network values are read-only, Roamer does not modify actual phone numbers or cell tower registration. Whether an app detects the override depends on which Telephony or Location APIs it queries.
Requirements
- Android 12+ (minSdk 31). Tested on Android 16 (Samsung).
- Shizuku running via Wireless Debugging or ADB.
READ_PHONE_STATEpermission granted on first launch to enumerate active SIM slots.- Per-app region override features require Android 13+ (System per-app locale API).
Technical Implementation
Privilege Escalation
Calling overrideConfig directly via Shizuku can fail on OEMs like Samsung because OEM security checks reject shell callers (getCallingUid() == SHELL).
To bypass this restriction without root:
- Roamer calls
IActivityManager.startInstrumentationvia Shizuku withINSTR_FLAG_NO_RESTART. - The instrumentation runs inside Roamer's own process and invokes
startDelegateShellPermissionIdentity(myUid, null). - This delegates shell permissions to Roamer's UID, allowing
overrideConfigto run withMODIFY_PHONE_STATEunder Roamer's caller identity rather than SHELL.
Baseline-Free Restore
Roamer does not persist pre-override snapshots. When restoring:
- The real country ISO is calculated from the immutable MCC (
getSimOperator). The restore operation writes back the real ISO first to update the subscription database, then clears the override layer (overrideConfig(null)). - The carrier name is automatically restored by clearing the override layer, which causes telephony services to pull the original carrier identifier on the next read.
Reflection & Hidden APIs
All hidden API accesses use HiddenApiBypass, avoiding compile-time hidden API stubs.
Building
export JAVA_HOME=/path/to/jdk-21
./gradlew :app:assembleDebug # Build debug APK
./gradlew :app:testDebugUnitTest # Run JVM unit tests
Project Structure
com.eigenlux.roamer/
├── core/ # Telephony APIs, Shizuku bindings, and instrumentation logic
│ ├── ShizukuManager
│ ├── CarrierConfigController
│ ├── InstrumentationTrigger
│ ├── PrivilegedOverrideInstrumentation
│ ├── PrivilegedSubscriptionReader
│ ├── RegionLogic
│ └── LocaleOverrideController
├── data/ # Region/carrier presets and local app state storage
├── ui/ # Compose UI, Material 3 theme, and main activity
└── AppPickerScreen.kt
Internationalization
UI text is defined in res/values (English default) and res/values-zh (Chinese). A JVM unit test (StringsParityTest) checks string key parity across translation files.
Limitations
- Privilege delegation was designed around Samsung's shell UID restrictions on Android 12-16. Other OEM implementations are supported on a best-effort basis.
- If a SIM loses connection (e.g., airplane mode) during operation, telephony state updates may lag behind UI confirmation.
License
MIT License. See LICENSE for details.
Acknowledgements
Inspired by earlier Shizuku-based carrier override tools:
How Shizuku is used
Can spoof SIM country and carrier name, show SIM IDs and sync app languages via `Shizuku`.
This is an AI-assisted analysis of Shizuku-related usages in the app's public source code. It is best effort, so it may not catch every single usage.
How this app uses Shizuku
Roamer uses Shizuku to present a different mobile country, carrier name and app language than the inserted SIMs provide.
- Spoof SIM country and carrier: pick a country and carrier name for one SIM, or tap a quick switch country to apply it to all SIMs, applied through Shizuku as a carrier settings override.
- Restore original network info: restore one SIM or all overridden SIMs at once, returning the displayed country to the real value derived from the SIM and clearing the custom carrier name through Shizuku.
- Show SIM identifiers: display each SIM slot with its subscription and card identifiers, reading the normally hidden card identifier through Shizuku when available.
- Sync app languages: enroll installed apps to follow the primary SIM country language and toggle the follow switch, reading and setting each selected app language through Shizuku, with the original language restored when unenrolled or switched off.
Android APIs or commands used
IActivityManager.startInstrumentationIActivityManager.startDelegateShellPermissionIdentityIActivityManager.stopDelegateShellPermissionIdentityCarrierConfigManager.overrideConfigICarrierConfigLoader.notifyConfigChangedForSubIdISub.getActiveSubscriptionInfoListILocaleManager.getApplicationLocalesILocaleManager.setApplicationLocales
Notable details
Overrides prefer a persistent mode that can survive reboot where the system allows it, otherwise they last until reboot. All override, restore, card identifier and app language actions require Shizuku to be running and granted, with no alternate privileged path in the current source.
Changelog
What's new for version 1.0.1
Permissions
4 permissions requested