Full but still broken rework of everything

This commit is contained in:
2026-05-08 19:28:57 +02:00
parent e5471b5fa0
commit 3aa0470bcf
56 changed files with 2247 additions and 1552 deletions
+156
View File
@@ -0,0 +1,156 @@
# CamSwapper — Project Status
## Build Status
- **Both flavors compile**: `modernDebug` and `legacyDebug` assemble successfully with 0 errors, 0 warnings (minor `extractNativeLibs` manifest warning from AGP).
- **On-device test**: Installed on Pixel 9a (Android 16). FGS crash resolved with `specialUse` type. App now has Application class, INTERNET + POST_NOTIFICATIONS permissions, and custom notification icon.
- **Min SDK**: 29 | **Target SDK**: 36 | **Compile SDK**: 36
- **Kotlin**: JVM 11, toolchain 17
- **Gradle**: 8.13
## Recent Changes
1. **Removed Xposed framework dependency** — all Xposed APIs (IXposedHookLoadPackage, ReflectionTools, process-based hooks) deleted.
2. **Cleaned up Xposed remnants** — removed `src/modern/resources/META-INF/xposed/`, `src/legacy/AndroidManifest.xml` (xposed metadata), and `src/legacy/assets/` (xposed_init files).
3. **Moved `ConfigRepository.kt`** from `src/modern/java/` to `src/main/java/` so both product flavors can compile (MediaType/MediaSource enums needed by main source set files).
4. **Rewrote `VirtualCameraService.kt`** (485 corrupted lines → 327 clean lines):
- Uses reflection for `@SystemApi` VDM types (`VirtualDeviceManager`, `VirtualDeviceParams`, `VirtualCameraConfig`, `VirtualCameraCallback`, `DeviceFilter.Builder`)
- Uses direct API for public companion types (`CompanionDeviceManager`, `AssociationRequest`, `AssociationInfo`)
- Single clean `VirtualCameraCallback` proxy wired to `VideoPusher` pipeline
- Proper CDM association flow with fallback to dummy ID
- Removed 4x duplicated callback blocks, broken braces, dangling code
5. **Fixed `foregroundServiceType` for SDK 36** — On-device test on Pixel 9a (Android 16) revealed `mediaProjection` FGS type requires `FOREGROUND_SERVICE_MEDIA_PROJECTION` + `CAPTURE_VIDEO_OUTPUT` permissions on target SDK 36. Changed to `specialUse` with `PROPERTY_SPECIAL_USE_FGS_SUBTYPE` declaration. APK now installs without crash on boot.
6. **Added `CamSwapperApp` Application class**`GlobalState.appContext` was `lateinit` and never initialized, causing potential crash when `VideoPusher.start()` or `SourceManager` accessed it. Now properly initialized in `Application.onCreate()`.
7. **Added missing permissions**`INTERNET` (needed by ExoPlayer/Media3), `POST_NOTIFICATIONS` (for Android 13+ notification permission compliance).
8. **Replaced notification icon**`android.R.drawable.ic_menu_camera` (system resource, may be unavailable) replaced with custom `R.drawable.ic_notification`.
## Architecture Overview
```
app/src/main/java/com/nothing/camera2magic/
├── MainActivity.kt # Entry point, permission flow, service bind
├── VirtualCameraService.kt # Foreground service → VirtualDeviceManager via reflection
├── GlobalState.kt # Global app context holder
├── viewmodel/
│ ├── ConfigRepository.kt # SharedPreferences-backed config (MediaType, MediaSource enums)
│ ├── SpotlightViewModel.kt # Media selection & preview state (MVI + StateFlow)
│ ├── SettingsViewModel.kt # App settings + HAL mode toggle
│ ├── ViewModelFactory.kt # ViewModel provider factory
│ └── CompositionLocals.kt # Compose DI locals
├── view/
│ ├── SpotlightView.kt # Media source selector, preview grid, module switch
│ └── SettingsView.kt # Toggle settings + HAL mode config
├── hook/
│ ├── SourceManager.kt # Media content resolver & fingerprint checking (224 lines)
│ ├── VideoPusher.kt # ExoPlayer → Surface → VirtualCameraRenderer pipeline
│ ├── VirtualCameraRenderer.kt # OpenGL ES renderer, SurfaceTexture → EGL → ImageWriter (387 lines)
│ ├── NativeBridge.kt # JNI bridge for native C++ camera HAL hooks
│ ├── HalConfigManager.kt # Root-based HAL config writer (/data/local/camera_magic/)
│ ├── BlackHoleMapper.kt # Empty/dummy camera HAL mapper
│ └── CameraState.kt # Camera state tracking
├── ui/theme/
│ ├── Color.kt, Theme.kt, Type.kt # Material3 theme
└── utils/
└── Dog.kt # Logging utility
```
## Product Flavors
| Flavor | Purpose |
|---------|---------|
| `legacy` | Devices without VirtualDeviceManager support (Android 10-13) — currently identical to modern |
| `modern` | Devices with Android 14+ VirtualDeviceManager API — has additional hardware buffer path available |
## Pipeline: Media → Virtual Camera
```
Local Media (ContentResolver) or Network (RTSP)
VideoPusher (ExoPlayer) / SourceManager
VirtualCameraRenderer (OpenGL ES)
│ SurfaceTexture → EGL → ImageWriter
VirtualCameraService (reflection)
│ VirtualDeviceManager → VirtualCamera
Other apps see a virtual camera device
```
## Component Details
### VirtualCameraService (reflection-based)
- **Status**: Compiles ✅, refactored ✅ (327 lines, clean architecture)
- **API level gate**: Build.VERSION_CODES.UPSIDE_DOWN_CAKE (34)
- **Approach**: Reflection for `@SystemApi` types (`VirtualDeviceManager`, `VirtualDeviceParams`, `VirtualCameraConfig`, `VirtualCameraCallback`, `DeviceFilter.Builder`). Direct API for public companion types (`CompanionDeviceManager`, `AssociationRequest`, `AssociationInfo`, `DeviceFilter`)
- **Callback**: `VirtualCameraCallback` proxy wired — `onStreamConfigured()` feeds the `Surface` to `VideoPusher.start()`
- **CDM**: Full `CompanionDeviceManager.associate()` flow with `DeviceFilter.FEATURE_VIRTUAL_CAMERA` filter, plus fallback to dummy ID 1 when CDM unavailable or association fails
- **VideoPusher integration**: Uses `VideoPusher` singleton object directly (`VideoPusher.start()`, `VideoPusher.stop()`)
- **Previously**: 485 corrupted lines with 4x duplicated callback blocks, broken braces, dangling code, no callback wiring, `VideoPusher.getInstance()` dependency that didn't exist
### ConfigRepository
- **Status**: Clean ✅
- Backs all settings via SharedPreferences
- Enums: `MediaSource` (LOCAL/NETWORK), `MediaType` (VIDEO/IMAGE)
- HAL mode settings also stored here
### SourceManager
- **Status**: ✅ Compiles, legacy footprint from Xposed era
- Global singleton, manages media source selection & fingerprinting
- Directly accesses ContentResolver for local media
- Still uses `moduleEnabled` concept from Xposed module days
### VideoPusher + VirtualCameraRenderer
- **Status**: ✅ Compiles (OpenGL ES + ExoPlayer pipeline)
- VideoPusher: Singleton object, takes a video ID via `start(surfaces, width, height, videoId)`, creates ExoPlayer, feeds to renderer surfaces
- VirtualCameraRenderer: 387-line OpenGL ES 2.0 renderer, handles EGL setup, SurfaceTexture → ImageWriter pipeline
- VideoPusher is wired via `VirtualCameraCallback.onStreamConfigured()` in VirtualCameraService
### HalConfigManager
- **Status**: ✅ Compiles, requires root
- Writes config to `/data/local/camera_magic/config.txt` via `su -c`
- Called from SettingsViewModel HAL mode toggle
## Remaining Work / Known Issues
### Critical
- (none — all previously identified critical issues resolved)
### Medium
- [ ] **SourceManager duplicates ConfigRepository** — SourceManager has its own SharedPreferences keys and module state, duplicating ConfigRepository. Should be consolidated.
- [ ] **Native bridge stub**`NativeBridge.kt` exists but no native `.so` is loaded (CMake/NDK build disabled). The project uses prebuilt `libcamera3.so` from jniLibs.
- [ ] **legacy flavor** — Both flavors currently have identical source sets. The `legacy` flavor should ideally strip out VirtualDeviceManager-dependent features.
### Low / Cleanup
- [ ] **Test files**`ExampleInstrumentedTest.kt` and `ExampleUnitTest.kt` are the default Android Studio stubs.
- [ ] **GlobalState.kt** — Legacy singleton used by Xposed hooks; may be removable now.
- [ ] **`Dog` utility** — Thin wrapper over `android.util.Log`.
## Module Projects (outside `app/`)
| Directory | Purpose |
|-----------|---------|
| `root-module/` | KernelSU module packaging (HAL-level camera hook) |
| `zygisk-module/` | Zygisk module packaging (injection-based) |
| `native/` | C++ native code for camera HAL hooks |
| `docs/` | Documentation assets |
| `camswapper-kernelsu-v2.zip` | Prebuilt KernelSU module |
| `camswapper-zygisk-v2.zip` | Prebuilt Zygisk module |
## Build Commands
```bash
# Build modern flavor (VirtualDeviceManager + system APIs)
./gradlew :app:assembleModernDebug
# Build legacy flavor (no system APIs)
./gradlew :app:assembleLegacyDebug
# Build with native C++ compilation
./gradlew :app:buildNative
# Build release
./gradlew :app:assembleModernRelease
```