Linear: https://linear.app/engineereddev/issue/ENG-266
What's in this PR (104 files, all under apps/android/):
- Send:
ShareActivityhandlesACTION_SENDwithEXTRA_STREAMandACTION_SEND_MULTIPLE(one push per file); the Home composer gets Attach (ACTION_OPEN_DOCUMENT, multiple). Name, MIME and size viaOpenableColumns;ciphertextSizechecked againstmaxFileBytesbefore reserving. UploadWorker(expedited where allowed, foreground progress on channeltransfers):POST /api/files→ stream-encrypt withFileCryptothrough an OkHttpRequestBodyof known length to the presigned (direct) or proxy URL →POST /api/pushes; retries on network errors, 429 and 5xx (ENG-264 classification). Source content is snapshotted to private cache (also for picker documents, so retries never re-encrypt changed bytes under the same key) and deleted afterwards; job metadata is encrypted.- Receive: the notification's Download →
DownloadWorker:GET /api/files/:id→ stream → decrypt →MediaStore.Downloads/Pneumo/<name>(API 29+) or app-specific Downloads (26–28), with progress; the same notification becomes Open / Share; tag failure deletes the partial file and shows "This file was corrupted or tampered with"; collisions → "name (1).ext". Home file rows get Download / Open / Share. Notification identity and the group summary rules from ENG-263 are preserved (new group regressions). - Generic downloaded MIME types fall back to the file extension for Open/Share; explicit MIME types win.
- Tests: worker tests with MockWebServer +
WorkManagerTestInitHelper(round trips 0 B / 1 B / 65,536 B / 1 MB, direct and proxy endpoints, tamper cleanup, retry), share-intent parsing, managed-device file exchange; 24 new goldens and 30 re-recorded (named in the commit). New test dependency:androidx.work:work-testing:2.12.0.
Verify (lead, rebased on 0ceccf2):
mise run check:android→ exit 0./gradlew testDebugUnitTest --rerun→ exit 0 (335 tests, 0 failures)./gradlew pixel6Api34DebugAndroidTest --rerun→ exit 0 (14 tests, 0 failures)- Acceptance (implementer, API 34 emulator, local random-port server): Photos → share → Pneumo →
dev-client downloadbyte-identical;dev-client send file→ notification Download → Open in Photos; SHA-256 matched both ways. Lead checked the Download-complete notification with Open/Share.
Deviations: picker documents are snapshotted to private cache rather than kept by persistable grant; MIME fallback by extension for generic types.
🤖 Generated with Claude Code