File Manager
An ad-free, one-time-paid Android file manager. It browses and manages the files on your device — locally, with no ads, no account and no analytics.
Nothing ever leaves the device: the app declares no network permission and contains no advertising or tracking SDKs.
Working title. The display name and the store listing are decided before the first Play upload (see docs/ROADMAP.md, M10). The
applicationIdis already fixed and can never change after the first release.
Status
M7 — on-device validation: done. Run on a real Xiaomi M2101K7AG (Android 12/MIUI). The permission flows, real-storage browsing, the text editor's read/write path and the storage-usage screen were all exercised on hardware, and two real defects were found and fixed. See docs/EDGE_CASE_TESTING.md.
Tech stack
| Area | Choice |
|---|---|
| Language | Kotlin 2.4.10 (using AGP 9 built-in Kotlin) |
| UI | Jetpack Compose, BOM 2026.06.01, Material 3 |
| Build | Gradle 9.3.1, Android Gradle Plugin 9.1.0 |
| Storage access | MANAGE_EXTERNAL_STORAGE ("All files access") with a Storage Access Framework fallback |
| Archives | Apache Commons Compress (pure Java — no NDK) |
| SDK levels | compileSdk/targetSdk 36, minSdk 26 |
targetSdk is 36 because Google Play requires new apps and updates to target
Android 16 (API 36) from 31 August 2026.
Project layout
app/src/main/java/de/softwareapp_hb/filemanager/
├── core/ Pure-Kotlin engine (no Android imports!) — paths, sorting, formatting,
│ search matching, copy/move planning, conflict policy
├── data/ Storage backends (all-files access + SAF), volumes, bookmarks,
│ file operations, archives, deletion
├── domain/ Browser + operation controllers, models, permission state
├── service/ Foreground service for long-running file operations
├── ui/ Compose theme, browser screen, components, ViewModels
└── text/ Domain enum → string-resource mapping
app/src/test/java/… JVM unit tests for the core engine
core/ deliberately has no Android dependencies, so the trickiest logic is
covered by fast JVM tests.
Building
Prerequisites:
- JDK 17+ (JDK 25 verified)
- Android SDK with
platforms;android-36andbuild-tools;36.0.0
# Tell Gradle where the SDK lives (this file is git-ignored)
echo "sdk.dir=$HOME/Android/Sdk" > local.properties
./gradlew :app:assembleDebug # debug APK
./gradlew :app:testDebugUnitTest # JVM unit tests for the engine
./gradlew :app:lintDebug # Android Lint
./gradlew :app:bundleRelease # Play upload bundle (.aab)
Release signing is optional and driven by a git-ignored keystore.properties
(see keystore.properties.example); without it the release build still runs
R8/minification but produces an unsigned artefact.
Tracked in git
- Source, resources and Gradle build files.
docs/— roadmap and release documentation.PRIVACY.md,CHANGELOG.md, and (from M10)store-assets/.
Not tracked: local.properties, keystore.properties, *.jks, build outputs.
Releasing
Release signing is driven by the git-ignored keystore.properties (see
keystore.properties.example). Without that file the release build still runs R8 and
resource shrinking, but produces an unsigned artefact that cannot be uploaded.
./gradlew :app:bundleRelease # Play upload bundle (.aab)
./gradlew :app:assembleRelease # APK, for local checks
# Audit what is actually shipped — in particular that there is no INTERNET permission:
$ANDROID_HOME/build-tools/36.0.0/aapt2 dump permissions \
app/build/outputs/apk/release/app-release.apk
Read docs/PLAY_RELEASE_CHECKLIST.md before uploading. Step 4 is the one that matters most for this app: a file manager must declare "All files access" through Play's Permissions Declaration Form, and have the core purpose documented in its store description. PRIVACY.md is written to match the shipped permissions.
Licence
Proprietary — all rights reserved.