A local Android music player scoped to a single folder (and its subdirectories). No cloud, no login, fast startup. Built for personal use on a Huawei Mate 50 Pro (HarmonyOS), but works on any Android API 26+.
- Folder-scoped library — pick any directory via Storage Access Framework; permission is persisted across launches.
- Recursive scan of
mp3,m4a,flac,aac,ogg,wav,opususing rawDocumentsContract(fast on big trees). - ID3 metadata + embedded album art read via
MediaMetadataRetriever; covers shown as row thumbnails (LRU-cached, decoded off-thread). - Background playback — Media3
MediaSessionServiceforeground service; lock-screen / notification controls. - Shuffle / Order toggle — persisted, applied via
Player.setShuffleModeEnabled. - Sleep timer — 15 / 30 / 45 / 60 / 90 min. End-time persisted to prefs so it survives process death; pause command routed via service intent so it works even when the Activity controller is released.
- Song list cache — scan results serialized per-folder; reopens with instant list, refreshes in background if files changed.
- Last folder remembered.
Kotlin · AndroidX · Material 3 · Media3 (ExoPlayer + Session) · ViewBinding · minSdk 26 · targetSdk 34.
export JAVA_HOME=/path/to/jdk-17
export ANDROID_SDK_ROOT=/path/to/android-sdk
./gradlew assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apkapp/src/main/java/com/shock/folderplayer/
├── MainActivity.kt single activity: folder picker, sleep timer, shuffle, MediaController glue
├── PlaybackService.kt Media3 MediaSessionService + sleep-pause intent handler
├── FolderScanner.kt DocumentsContract recursive walk + MediaMetadataRetriever
├── SongCache.kt JSON serialize/deserialize of the scanned list
├── SongAdapter.kt RecyclerView adapter with LRU-cached album art
└── Song.kt data class
MIT.