667a85f80c
The staged-delete work left a hole. The undo handle lived in BrowserUiState, so a delete from an earlier session was unreachable even though the files were sitting on the volume; and because nothing on disk recorded which folder an item came from, not even the user could put one back by hand with confidence. Adding a Trash screen alone would not have fixed it: the recovery data did not survive the process. So the origin is now written at delete time. data/ gains its first persistence: a SQLite index (staged path, original path, name, type, size, timestamp). SQLite rather than Room because an annotation processor is a large addition to this build for one table and three queries, and behind a TrashIndex port so domain/Trash keeps no Context while the tests drive it with a map and the real one is still tested against real SQLite. New Trash entry in the overflow menu lists batches and restores a whole one. The index is an index, not the truth: the staged files are the truth, and the two can disagree if a user empties the folder by hand or pulls a card. Reconciled both ways - restorableFrom drops entries whose file has gone, purgeExpired forgets entries whose folder has gone and sweeps folders no entry mentions - and rows are written after the move, so a crash leaves an unindexed folder (harmless, swept) rather than an entry that could never restore. Verified on hardware: delete, force-stop, relaunch, restore. Also corrects the docs where they claimed input swipe x y x y 900 is delivered as a plain tap on MIUI. It does open the selection bar - it was driven that way - but it has also landed as a tap, so it is flaky rather than impossible.
66 lines
4.5 KiB
Markdown
66 lines
4.5 KiB
Markdown
# On-device testing
|
||
|
||
What has actually been run on hardware, what it found, and what is still unverified. Keep
|
||
this file honest: an untested claim is a bug waiting to be reported.
|
||
|
||
## Devices used
|
||
|
||
| Device | Android | Notes |
|
||
|---|---|---|
|
||
| Xiaomi **M2101K7AG** (Redmi, `sunny`), MIUI V140 | 12 (API 31), arm64-v8a | A real phone with a real 55 GB library. Auto-rotate was on, so runs happened in both orientations. |
|
||
| AOSP `phone` AVD | 12 (API 31), x86_64 | Software emulation — the host exposes no `/dev/kvm`. Used from M0–M6. |
|
||
|
||
Connecting a phone to this dev container needs one fix: the USB node is created
|
||
`root:plugdev 0660`, and the container's user is not in `plugdev`, so adb cannot open it.
|
||
An udev rule widening the mode for Android vendors fixes it
|
||
(`/etc/udev/rules.d/51-android.rules`), after which `adb devices` sees the phone.
|
||
|
||
## Verified on the real device
|
||
|
||
| What | Result |
|
||
|---|---|
|
||
| First run, no permission granted | The "Choose a folder" prompt appears with both routes offered: *Grant full access* and *Choose folder*. Correct — the app has no source yet, so the SAF fallback is the honest state. |
|
||
| Granting "All files access" while the app is alive | The app picks it up on resume and switches from the prompt to the roots view, showing **"Internal storage · 50.0 GB free"** (matching `df`). The lifecycle refresh works. |
|
||
| Browsing real storage | Real folders listed alphabetically with correct icons and breadcrumbs ("Internal storage / Download"). Titles render "Internal storage", not the raw volume name. |
|
||
| Text editor, read | Tapping `a.txt` opened the editor showing its real content. |
|
||
| Text editor, **write** | Editing and tapping Save persisted to the device — verified independently with `adb shell cat`. |
|
||
| Storage usage | DCIM 2.7 GB / 668 files, Android 1.2 GB / 5925 files, Music 1.2 GB / 43 files, Pictures 866.4 MB / 5849 files, … sorted largest first with per-row share bars and correct plurals. |
|
||
| Revoking "All files access" mid-use | Returned to the folder prompt without crashing; the app kept running. Graceful degradation confirmed. |
|
||
| Landscape | The whole UI adapts (the phone auto-rotated mid-session): app bar, list, breadcrumbs and dialogs all laid out correctly. |
|
||
| `BACK` from the roots view | Exits the app, which is the expected Android behaviour. |
|
||
|
||
## Bugs this session found — both fixed
|
||
|
||
1. **The first-run copy was wrong.** The prompt read *"Full access was declined, so pick a
|
||
folder…"* on a device where the user had never declined anything. Reworded to
|
||
*"Without full access you can still work inside one folder you choose here."*, which is
|
||
true whether the user declined or simply has not granted yet. Re-verified on device.
|
||
2. **The storage-usage screen took ~45–60 seconds to show anything.** Measuring the root of
|
||
a real 55 GB volume blocked on the whole walk with only a spinner for company, which
|
||
reads as a hang. Two changes:
|
||
- `UsageAnalysis` now passes the `FileEntry` down the recursion instead of re-`stat`ing
|
||
every node (the parent's listing already says whether each child is a folder), so the
|
||
walk costs one listing per directory and nothing more.
|
||
- Rows are **published as they are measured** through an `onProgress` callback, and the
|
||
ViewModel appends them, re-sorting as it goes, so the biggest folders appear while the
|
||
rest of the tree is still being walked.
|
||
|
||
The UI never froze — the progress bar kept animating throughout, which confirms the I/O
|
||
stays off the main thread — but "slow and silent" is still a defect.
|
||
|
||
## Not verified, and why
|
||
|
||
- **Long-press multi-select via adb: it works, but not every time.** `input swipe x y x y 900`
|
||
*does* open the selection action bar on this MIUI build — it was driven that way to reach
|
||
Delete, Rename and Compress — but the same gesture has also landed as a plain tap, which
|
||
opens the row instead of selecting it. So the bar is reachable from the host, and yet
|
||
compress/extract from the UI is still worth a manual pass rather than trusted to a scripted
|
||
gesture. The archive engine itself is covered by end-to-end JVM tests, including a zip-slip
|
||
archive.
|
||
- **The SAF folder-picker round trip.** Driving the system picker and granting a tree was
|
||
not attempted; the code path is unit-tested against a stand-in `DocumentsProvider`.
|
||
- **Image viewer and thumbnails.** Verified on the AVD in M4/M5; not repeated on the phone.
|
||
- **The foreground-service notification** during a long copy. Started in M3 and unit-tested;
|
||
not observed on hardware.
|
||
- **Archive creation/extraction against real files.** Only exercised in-memory.
|