Uploading the bundle shows "This App Bundle contains native code, and you've not uploaded
debug symbols". Record the answer next to the upload step so it is not re-investigated on
every release:
- the bundle's only native code is libandroidx.graphics.path.so (4 ABIs, ~37 KB), which
arrives transitively through androidx.compose.ui:ui-graphics ->
androidx.graphics:graphics-path:1.0.1; this project builds no native code at all,
- ndk.debugSymbolLevel = "FULL" was tried and emits nothing for such a project (no
native-debug-symbols output, nothing added to the bundle), and
- the published AAR ships stripped libs only (symtab=0, no .debug_* sections, no symbol
entries at all), so there is no symbol file in existence to upload.
The warning is advisory and does not block review or rollout. Kotlin/Java stack traces are
already deobfuscated from the R8 mapping that rides inside the bundle, so the only thing
lost is symbolication of frames inside that Compose helper library.
Everything the Play forms ask for that can be settled from the working copy, settled:
- PRIVACY.md now carries the real contact address (softwareapp.hb@gmail.com), so the
policy publishes as-is. Hosting is the one step left that cannot be done from here,
because the repo has no git remote: step 5 of the checklist spells out the push +
GitHub Pages route and the URL it yields.
- Checklist: the screenshot item is done (four captures, 1080x2160, over the demo
library, no permission banner), the keystore and versionCode are recorded as already
in place - including the upload key's SHA-256 for the Play App Signing enrolment - and
the App access / Ads / remaining App content declarations are written down. The
first-upload release-notes question is answered too: versionCode is already 2, so
1.0.1 takes the *initial release* block, not the 1.0.1 one.
- The build facts were verified against the artefacts rather than the source: the
release APK reports versionCode=2, versionName=1.0.1, targetSdk=36 and exactly the
documented permission set, with no INTERNET in what actually ships.
- ROADMAP: the re-shoot row is struck out with the numbers that closed it, M10 no longer
claims the captures predate the demo library, and the demo library's removal is
recorded (MediaStore 5,386 -> 5,364; pruneTo drops the stale index rows next scan).
The staged state and the system confirmation dialog are documented as deliberately not
captured: staging clears the demo group, which would put real photos back in frame.
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.
store-assets/screenshots/ is git-ignored now, so the Graphics section and the
two blocker entries were describing a state that no longer exists. Point at
where the captures live instead, and say why screenshots stay out of git at
all: a screenshot of this app is a picture of a photo library.
The results screenshot is a screenshot *of a photo library*, so the committed
capture showed the developer's own photos. tools/make-demo-photos.py draws the
library instead: 22 procedural scenes (sunset, mountains, beach, conifers in
haze, dunes, city skyline, night sky, bokeh) with grain and a vignette, so there
are no people, no third-party content and nothing to license.
The duplicate structure is deliberate, because a folder of unrelated pictures
demonstrates nothing:
- headline group: one scene re-saved at falling quality and size until its
reclaimable size reaches --target-mb (45 MB). Results are ranked by
reclaimable bytes, so this group has to out-rank whatever is already on the
device or a real photo is the first thing back in frame.
- exact pair: two byte-identical files, for the SHA-256 path.
- singles: the other scenes, once each, so the library looks lived-in.
Verified with the app's own engine on the desktop before pushing anything:
22 images -> 2 groups (PERCEPTUAL 14 copies, EXACT 2 copies) with the six
singles left alone. Regeneration is byte-identical, the output path resolves
from __file__ so it runs from any cwd, and nothing is written outside the repo.
demo-photos/ is git-ignored, like fixtures/ and store-assets/raw-screenshots/.
STORE_LISTING.md documents the library, why the headline group has a target
size, the MediaProvider scan_file recipe and the cleanup step; ROADMAP, README
and the release checklist point at it.
An Android duplicate-photo finder. Pure-Kotlin core (SHA-256 + dHash hashing, exact and
perceptual union-find grouping, three sensitivity presets) with MediaStore access, a
persistent SQLite hash index and a tiered ScanEngine behind a Jetpack Compose UI.
No INTERNET permission, no ads, no analytics, no account.
Ships versionCode 2 / versionName 1.0.1, carrying the scan-stall hardening (BoundedCall
breaker) and verified against a 5,363-photo device library. 80 JVM unit tests, lint clean.
Release paperwork is in docs/ (Play checklist, store listing, edge-case testing), the
upload-ready Play graphics and screenshots in store-assets/, and the generators for those
assets in tools/.