Files
file-manager/CHANGELOG.md
T

5.7 KiB

Changelog

All notable changes to File Manager are documented in this file.

The format follows Keep a Changelog, and the project uses Semantic Versioning.

versionCode and versionName are defined in app/build.gradle.kts. Each Play upload needs a higher versionCode than every previous upload.

[Unreleased]

Added

  • M6 — release config and Play readiness. An upload keystore (4096-bit RSA, CN=Hadrian Burkhardt, L=Potsdam, C=DE) is generated and wired through the git-ignored keystore.properties, so bundleRelease produces a signed, R8-minified, resource-shrunk .aab (4 682 814 bytes) and assembleRelease a signed APK. docs/PLAY_RELEASE_CHECKLIST.md walks the Play Console work, with step 4 covering the Permissions Declaration Form for "All files access" — the declaration a file manager must make, and the one that can block a release. PRIVACY.md is written to match the shipped permissions: no collection, no sharing, no INTERNET. The shipped permission set is audited from the release APK.

  • M5 — analysis, archives and viewers. domain/UsageAnalysis rolls up recursive folder sizes and finds the largest files below a folder, which the new storage-usage screen shows as a size and a share bar per row. domain/ArchiveEngine creates ZIP archives and extracts ZIP, TAR, TAR.GZ, GZ, BZ2 and XZ using java.util.zip and Commons Compress — all pure Java, so the app still ships no native code; RAR and 7z are recognised and refused with a clear message rather than half-supported. Every archive entry name is passed through core/ArchivePath before it becomes a path, so a crafted ../ entry cannot write outside the destination. The browser gains Coil thumbnails in the list and grid, a built-in image viewer and text editor, and compress/extract actions. 26 new JVM tests (141 total), including a zip-slip archive that is refused while the same archive's safe entry still extracts.

  • M4 — the browser UI. The app is now usable end to end. StorageLocation (with a real StorageProvider and a fake for tests) decides which backend is in effect; BrowserViewModel owns navigation, sorting, hidden files, list/grid, search, selection and the clipboard, and turns an ASK conflict into a prompt rather than a guess. The screen offers roots and folder lists with breadcrumbs, a details sheet, new-folder / rename / delete / conflict dialogs, and the "All files access" and SAF-folder prompts — including an upgrade banner so declining full access never blocks browsing. Deletes go through the platform's own confirmation when MediaStore can build one and fall back to a direct delete otherwise; a FileProvider lets other apps open and receive files without a file:// URI ever leaving the process. 16 new JVM tests (115 total).

  • M3 — operations engine and foreground service. domain/FileOperations turns the backend primitives into copy, move, delete and rename: it walks folders, counts the work up front so the progress bar has an honest denominator, checks for cancellation between entries (never swallowing CancellationException), and reports per-item failures instead of abandoning a batch because one file was unreadable. Conflicts are resolved through the M1 TransferPlanner — ASK is deliberately surfaced to the caller so the UI can prompt. A move tries the backend's atomic rename first and only falls back to copy-then-delete when the backend cannot do it (the SAF path across directories); the source is never deleted when its copy failed. service/FileOpService is a dataSync foreground service that mirrors the engine's progress into an ongoing notification, so a long operation survives the app being backgrounded. 23 new JVM tests (99 total), including Robolectric coverage of the notification and the service entering the foreground.

  • M2 — storage layer. The two storage backends behind one interface. AllFilesSource is java.io.File over every mounted volume (the "All files access" path); SafSource is the Storage Access Framework fallback, reading a persisted tree URI through DocumentsContract with SafDocumentIds doing the tree↔path mapping and SafGrant owning the folder picker and its persistence. VolumeRepository enumerates volumes via StorageManager/StorageVolume and reports free/total space through StatFs; StorageAccess and StorageAccessPolicy decide between the two backends. Both sources confine their blocking I/O to Dispatchers.IO and expose a suspend contract. 32 new JVM tests (76 total), including a Robolectric run of SafSource against a stand-in DocumentsProvider.

  • M1 — pure-Kotlin core engine. An Android-free core/ package holding the logic every other layer builds on: StoragePath (normalised absolute paths that can never escape the root), FileEntry with extension-based FileKind classification and a MimeTypes lookup for "open with", natural-order SortSpec (directories always first, file2 before file10), human-readable FileSize, NameMatcher (case-insensitive substring plus */? globs), NameAllocator ("name (1)") and TransferPlanner (conflict policies and move-into-self detection). Covered by 44 JVM unit tests across 10 classes.

  • M0 — project scaffold. Gradle 9.3.1 / AGP 9.1.0 build with a version catalog, de.softwareapp_hb.filemanager app module, a Compose Material 3 shell with the branded blue theme (dynamic colour on Android 12+), an adaptive launcher icon, and the storage-access permission set (all files access + SAF fallback). Debug APK builds, installs and runs on an AOSP Android 12 AVD.