|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +**Pixel IMS** is an Android application that enables VoLTE (Voice over LTE) functionality on Google Tensor-powered Pixel devices without requiring root access. The app leverages Android's internal `telephony.ICarrierConfigLoader.overrideConfig()` API through Shizuku to override carrier configurations and enable IMS features. |
| 8 | + |
| 9 | +**Primary carriers supported:** |
| 10 | +- LG U+ (Republic of Korea) - 1st tier support |
| 11 | +- Various international carriers - 2nd tier (community-reported) |
| 12 | + |
| 13 | +**Target devices:** Google Pixel 6/6a/6 Pro, 7/7a/7 Pro, 8/8 Pro, Pixel Fold (Tensor chipset) |
| 14 | + |
| 15 | +## Build & Development Commands |
| 16 | + |
| 17 | +### Prerequisites |
| 18 | +This project requires a **patched android.jar** to compile successfully: |
| 19 | +1. Download the [patched android.jar](https://github.com/Reginer/aosp-android-jar/raw/main/android-34/android.jar) |
| 20 | +2. Place it under `$ANDROID_SDK/platforms/android-34/` |
| 21 | +3. This enables access to hidden Android APIs at compile-time |
| 22 | + |
| 23 | +### Build Commands |
| 24 | +```bash |
| 25 | +# Build debug APK |
| 26 | +./gradlew assembleDebug |
| 27 | + |
| 28 | +# Build release APK |
| 29 | +./gradlew assembleRelease |
| 30 | + |
| 31 | +# Install debug build to connected device |
| 32 | +./gradlew installDebug |
| 33 | + |
| 34 | +# Run lint checks |
| 35 | +ktlint --reporter=checkstyle,output=build/ktlint-report.xml |
| 36 | +``` |
| 37 | + |
| 38 | +### Testing |
| 39 | +Currently, this project does not have automated unit tests. Testing is performed manually by: |
| 40 | +- Installing the APK on a Tensor Pixel device |
| 41 | +- Verifying Shizuku permission grant |
| 42 | +- Toggling VoLTE settings |
| 43 | +- Checking IMS registration status |
| 44 | + |
| 45 | +## Architecture |
| 46 | + |
| 47 | +### Core Components |
| 48 | + |
| 49 | +**1. Moder Classes (`Moder.kt`)** |
| 50 | +- `Moder`: Base class providing access to hidden Android telephony services via Shizuku |
| 51 | + - `carrierConfigLoader`: ICarrierConfigLoader interface for carrier config overrides |
| 52 | + - `telephony`: ITelephony interface for telephony operations |
| 53 | + - `phoneSubInfo`: IPhoneSubInfo for subscription info |
| 54 | + - `sub`: ISub for subscription management |
| 55 | + |
| 56 | +- `CarrierModer`: Device-level operations |
| 57 | + - Get active subscriptions |
| 58 | + - Check device IMS support |
| 59 | + |
| 60 | +- `SubscriptionModer`: Per-SIM operations |
| 61 | + - Override carrier configs (VoLTE, VoWiFi, VoNR, etc.) |
| 62 | + - Query current config values |
| 63 | + - Restart IMS registration |
| 64 | + |
| 65 | +**2. Shizuku Integration (`Utils.kt`)** |
| 66 | +- `checkShizukuPermission()`: Verifies Shizuku service is running and permission is granted |
| 67 | +- Shizuku provides ADB-level privileges without root to call hidden system APIs |
| 68 | + |
| 69 | +**3. UI Layer** |
| 70 | +- Built with **Jetpack Compose** and Material 3 |
| 71 | +- `HomeActivity.kt`: Main entry point with bottom navigation |
| 72 | +- Navigation structure: |
| 73 | + - `/home`: Overview page showing app status |
| 74 | + - `/config{subscriptionId}`: Per-SIM configuration page |
| 75 | + - `/config{subscriptionId}/dump`: Raw config dump viewer |
| 76 | + - `/config{subscriptionId}/edit`: Expert mode editor |
| 77 | + |
| 78 | +**4. Hidden API Access** |
| 79 | +- Uses `HiddenApiBypass` library to bypass Android's hidden API restrictions |
| 80 | +- AIDL interfaces (`IPrivilegedService.aidl`) for Shizuku service binding |
| 81 | + |
| 82 | +### Key Configuration Keys |
| 83 | +The app primarily modifies these `CarrierConfigManager` keys: |
| 84 | +- `KEY_CARRIER_VOLTE_AVAILABLE_BOOL`: Enable VoLTE |
| 85 | +- `KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL`: Enable VoWiFi |
| 86 | +- `KEY_CARRIER_VT_AVAILABLE_BOOL`: Enable Video Telephony |
| 87 | +- `KEY_VONR_ENABLED_BOOL`: Enable VoNR (5G voice) |
| 88 | +- `KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL`: Enable cross-SIM calling |
| 89 | + |
| 90 | +## Important Development Notes |
| 91 | + |
| 92 | +### Hidden API Bypass |
| 93 | +On app startup (`HomeActivity.onCreate`), the app adds hidden API exemptions: |
| 94 | +```kotlin |
| 95 | +HiddenApiBypass.addHiddenApiExemptions("L") // Classes starting with L |
| 96 | +HiddenApiBypass.addHiddenApiExemptions("I") // Interfaces starting with I |
| 97 | +``` |
| 98 | + |
| 99 | +### Interface Caching |
| 100 | +The `Moder` class implements `loadCachedInterface()` to cache Binder interfaces and avoid repeated service lookups, improving performance. |
| 101 | + |
| 102 | +### Subscription Handling |
| 103 | +- The app dynamically generates navigation routes based on active SIM subscriptions |
| 104 | +- Each SIM gets its own config page with unique subscription ID |
| 105 | +- Uses `SubscriptionInfo.uniqueName` extension: `"${displayName} (SIM ${simSlotIndex + 1})"` |
| 106 | + |
| 107 | +### IMS Registration Check |
| 108 | +VoLTE status is verified via: |
| 109 | +1. `SubscriptionModer.isIMSRegistered`: Programmatic check using `ITelephony.isImsRegistered()` |
| 110 | +2. User can also check via dialer codes: `*#*#4636#*#*` → Phone information → IMS Service Status |
| 111 | + |
| 112 | +### Version Updates |
| 113 | +The app checks GitHub Releases API for updates: |
| 114 | +```kotlin |
| 115 | +getLatestAppVersion { latestVersion -> |
| 116 | + // Compare with BuildConfig.VERSION_NAME |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +## CI/CD |
| 121 | + |
| 122 | +### GitHub Actions Workflows |
| 123 | +- **default.yml**: Runs ktlint on PRs, builds debug APK, posts download link as PR comment |
| 124 | +- **build-apk.yml**: Reusable workflow for building APKs with signing |
| 125 | +- **build-aab.yml**: Builds Android App Bundle for Play Store releases |
| 126 | +- **build-debug-apk.yml**: Standalone debug build workflow |
| 127 | + |
| 128 | +### Linting |
| 129 | +The project uses **ktlint 0.48.2**. Lint violations will fail CI checks on PRs affecting `app/src/**`. |
| 130 | + |
| 131 | +## Distribution |
| 132 | + |
| 133 | +The app is distributed via: |
| 134 | +1. **Google Play Store**: `dev.bluehouse.enablevolte` |
| 135 | +2. **GitHub Releases**: Direct APK download |
| 136 | + |
| 137 | +## Troubleshooting Development Issues |
| 138 | + |
| 139 | +### Build Failures |
| 140 | +- **Missing hidden API classes**: Ensure patched `android.jar` is installed at `$ANDROID_SDK/platforms/android-34/` |
| 141 | +- **Shizuku not working**: Shizuku must be running via ADB or wireless debugging before launching the app |
| 142 | + |
| 143 | +### Common Runtime Issues |
| 144 | +- **Shizuku permission denied**: App will prompt for permission; grant "Allow all the time" |
| 145 | +- **IMS not registering**: After toggling VoLTE, restart device 2-3 times with 5-minute intervals |
| 146 | +- **Post-system update**: VoLTE configuration must be re-applied after Android system updates |
| 147 | + |
| 148 | +## Code Style |
| 149 | + |
| 150 | +Follow standard Kotlin conventions and ktlint rules. Use Jetpack Compose best practices for UI components. |
0 commit comments