docs: record the store screenshot re-shoot over the demo library
The three captures no longer show the "Photo access needed" banner, and the results screen is a picture of the generated demo library instead of the developer's own. Both caveats in the file are closed, so replace them with a short note on how the set was actually taken: - 01-empty: the grant went through the app's own "Grant access" button, so checkSelfPermission is genuinely satisfied. This one needed no tap at all: results and the selection live in ScannerViewModel and only the hash index is persisted, so force-stop + relaunch returns to the empty state with the grant still in place. - 02-scanning / 03-results: shot after tapping Scan over the demo library. The headline group is 43.1 MB reclaimable, which out-ranks the biggest group already on the device (39.8 MB), so the first group in frame is generated. - 04-options is new: the Options DropdownMenu with the three sensitivity presets (it is not a bottom sheet) and the trash-vs-permanent toggle. The tick marks and the "37 selected" bar are the screen's default state, not a staged tap -- a finished scan auto-selects all but best. MIUI still refuses pm grant and synthetic taps (INJECT_EVENTS), so Grant access and Scan remain the two taps a human has to make; the two screens still missing (the staged state and the system consent dialog) are captured by watching for UI text changes instead, rather than by timing a scripted tap.
This commit is contained in:
+41
-28
@@ -26,7 +26,7 @@ python3 tools/make-demo-photos.py # synthetic photo library -> demo-photos/ (gi
|
||||
|---|---|---|---|
|
||||
| App icon | 512×512, 32-bit PNG with alpha, ≤ 1 MB | `store-assets/icon-512.png` — 512×512, RGBA, 6 KB | `tools/store-assets/icon.svg`, mirrored from `app/src/main/res/drawable/ic_launcher_background.xml` + `ic_launcher_foreground.xml` (paths and group transforms are identical, so the store icon *is* the launcher icon) |
|
||||
| Feature graphic | 1024×500, JPEG or 24-bit PNG without alpha | `store-assets/feature-graphic-1024x500.png` — 1024×500, RGB | `tools/store-assets/feature-graphic.svg` |
|
||||
| Phone screenshots | JPEG or 24-bit PNG without alpha, shorter side ≥ 320 px, longer side ≤ 3840 px, **longer side ≤ 2× shorter side** | `store-assets/screenshots/0{1,2,3}-*.png` — 1080×2160, RGB | `tools/make-store-screenshots.sh`, from raw `adb exec-out screencap` captures in `store-assets/raw-screenshots/` |
|
||||
| Phone screenshots | JPEG or 24-bit PNG without alpha, shorter side ≥ 320 px, longer side ≤ 3840 px, **longer side ≤ 2× shorter side** | `store-assets/screenshots/0{1,2,3,4}-*.png` — 1080×2160, RGB | `tools/make-store-screenshots.sh`, from raw `adb exec-out screencap` captures in `store-assets/raw-screenshots/` |
|
||||
|
||||
Two details worth keeping in mind:
|
||||
|
||||
@@ -44,27 +44,37 @@ Captured on the test device (1080×2400, Android 12 / MIUI), cropped to 1080×21
|
||||
|
||||
| File | Screen |
|
||||
|---|---|
|
||||
| `01-empty.png` | Intro / empty state before the first scan |
|
||||
| `02-scanning.png` | Scanning progress — *“Looking for visually similar photos…”* 5341 / 5363 |
|
||||
| `03-results.png` | Results — 15 duplicate groups, 39.8 MB reclaimable, `BEST` badge, selection bar |
|
||||
| `01-empty.png` | Intro / empty state before the first scan — access already granted, so there is no banner and *Start scan* is enabled |
|
||||
| `02-scanning.png` | Scanning progress — *“Looking for visually similar photos…”* 5353 / 5385, live *Cancel* |
|
||||
| `03-results.png` | Results over the demo library — 17 duplicate groups, 54 of 5385 photos, 83.5 MB reclaimable, the generated 14-copy group first, `BEST` badge, selection bar |
|
||||
| `04-options.png` | Options menu (`DropdownMenu` off the top bar) — the three sensitivity presets with the ✓ on the active *Balanced (recommended)*, and the trash-vs-permanent toggle |
|
||||
|
||||
⚠️ **Both caveats below are outstanding for the three captures currently in
|
||||
`store-assets/screenshots/`.** One re-shoot fixes both.
|
||||
The tick marks and the *37 selected · 83.5 MB* bar in `03-results.png` are not a staged tap: a
|
||||
finished scan auto-selects *all but best* across every group (`ScannerViewModel.autoSelection`),
|
||||
so that **is** the screen's default state.
|
||||
|
||||
1. All three still show the *“Photo access needed”* banner. The test device (Xiaomi M2101K7AG
|
||||
/ MIUI) refuses `pm grant`, `install -g` and synthetic taps, so the runtime permission was
|
||||
never actually granted there — the scan was driven with a debug-only
|
||||
`MANAGE_EXTERNAL_STORAGE` app-op. That app-op gets the scan through MediaStore but does
|
||||
**not** satisfy the app's own `checkSelfPermission`, which is why the banner — and the
|
||||
disabled *Start scan* — are genuinely in frame. **Re-shoot on a clean install after tapping
|
||||
“Grant access”**: that also closes the one remaining device-only verification gap.
|
||||
The two earlier caveats are closed. The current captures were re-shot through the app's own
|
||||
permission flow and over the generated demo library:
|
||||
|
||||
Enabling *USB debugging (Security settings)* in the MIUI developer options turns synthetic
|
||||
taps and `pm grant` back on. That is what would let the capture run from a script instead of
|
||||
by hand.
|
||||
2. `03-results.png` currently shows real photos from the test library. They are the developer's
|
||||
own, so nothing is licensed against us, but the library is not ours to publish. The next
|
||||
capture must be taken over the generated demo library below.
|
||||
1. **No *“Photo access needed”* banner.** The runtime grant went through the app's *Grant access*
|
||||
button, so `checkSelfPermission` is genuinely satisfied. The test device (Xiaomi M2101K7AG /
|
||||
MIUI) still refuses `pm grant`, `install -g` and synthetic taps (`SecurityException:
|
||||
Injecting to another application requires INJECT_EVENTS`), so *Grant access* and *Scan* are
|
||||
the two taps a human has to make. Enabling *USB debugging (Security settings)* in the MIUI
|
||||
developer options is what would make the whole capture run scriptable.
|
||||
2. **No real photos in frame.** `03-results.png` was shot over the demo library below, and its
|
||||
headline group (43.1 MB reclaimable) outranks the biggest group already on the device
|
||||
(39.8 MB), so the first thing on screen is a generated sunset instead of somebody's library.
|
||||
|
||||
Only *Scan* needed a tap in the end. `01-empty.png` did not: scan results and the selection live
|
||||
in `ScannerViewModel` (only the hash index is persisted), so force-stopping and relaunching the app
|
||||
returns to the empty state with the grant still in place:
|
||||
|
||||
```bash
|
||||
adb shell am force-stop de.softwareapp_hb.fotodup.finder.debug
|
||||
adb shell am start -n de.softwareapp_hb.fotodup.finder.debug/de.softwareapp_hb.fotodup.finder.MainActivity
|
||||
adb exec-out screencap -p > store-assets/raw-screenshots/01-empty.png
|
||||
```
|
||||
|
||||
### Demo library: generated photos, so none of anyone's real ones are published
|
||||
|
||||
@@ -94,9 +104,10 @@ Two non-obvious details, both load-bearing:
|
||||
|
||||
- **Why the headline group has a target size.** Results are ranked by reclaimable bytes, so the
|
||||
first group on screen is the largest one. A demo group smaller than anything already on the
|
||||
device would be pushed below the fold and a real photo would be back in frame. 45 MB clears
|
||||
the test device's own 39.8 MB with room to spare; raise `--target-mb` if you capture on a
|
||||
library whose biggest group is larger.
|
||||
device would be pushed below the fold and a real photo would be back in frame. The default
|
||||
`--target-mb 45` yields a headline group of **43.1 MB reclaimable**, which clears the test
|
||||
device's own 39.8 MB with room to spare; raise `--target-mb` if you capture on a library whose
|
||||
biggest group is larger.
|
||||
- **`scan_file` on the folder, not on the volume.** It indexes just that path (API 30+) instead
|
||||
of forcing a MediaStore-wide rescan on a 5,000-photo device. It does recurse into the folder,
|
||||
and re-running it after the folder is deleted drops those rows again — both verified on the
|
||||
@@ -121,13 +132,15 @@ adb shell rm -rf /sdcard/DCIM/foto-dup-demo
|
||||
adb shell content call --uri content://media --method scan_file --arg /sdcard/DCIM/foto-dup-demo
|
||||
```
|
||||
|
||||
Screens still worth capturing once a device grants access through the real flow (the capture run
|
||||
needs two taps on the phone — *Grant access*, then *Scan* — which is the one thing the MIUI test
|
||||
device will not accept from a script):
|
||||
Two more screens are worth adding to the set. Each needs a tap, and MIUI only accepts taps from a
|
||||
human, so they are captured by hand — a loop that takes a `uiautomator dump` and screencaps whenever
|
||||
the UI **text** changes is enough, so the capture never depends on tap timing. That is how
|
||||
`04-options.png` was taken, and it catches the menu, the staging and a system dialog in one pass:
|
||||
|
||||
- the **Options** sheet with the three sensitivity presets,
|
||||
- the staged state (*“All duplicates are ready to go”*) after selecting duplicates,
|
||||
- Android's **confirmation dialog** for moving photos to the trash.
|
||||
- the staged state (*“All duplicates are ready to go”*) after *Remove all selected*. Nothing is
|
||||
deleted at that point and no dialog appears yet — the rows simply leave the list.
|
||||
- Android's **confirmation dialog** for the whole batch, which *Apply* launches. Dismissing it is
|
||||
non-destructive: the staging is kept, and *Apply* can be tapped again.
|
||||
|
||||
## Store listing copy
|
||||
|
||||
|
||||
Reference in New Issue
Block a user