Documentation only. Two results from #223–#230 that belong with the read rather than only in their own tickets, plus the outcome column for the ticket table.
E7 — a real DocumentsProvider cannot be reached without the picker
#226 split into a cheap headless half and an expensive picker-driven one, on the premise that a real DocumentsProvider can be reached without DocumentsUI. It cannot — measured three ways on API 34:
approach
result
a DOCUMENTS_PROVIDER without MANAGE_DOCUMENTS
refused at install: "Provider must be protected by MANAGE_DOCUMENTS"
create as the test APK, which owns the provider
denied — instrumentation runs in the target app's process, so it carries the app's uid
adoptShellPermissionIdentity(MANAGE_DOCUMENTS)
denied identically
Each denial names the only way in: "you obtain access using ACTION_OPEN_DOCUMENT or related APIs". And the intent filter is not optional — without it isDocumentUri returns false, which is exactly the branch guarding deletePartialOutput.
So #226 is one item at the picker's cost, not two. The ticket was updated to say so.
The useful half of the distinction: the input bridge needs no documents provider at all. getSafParameterForRead opens a descriptor through the resolver, so any readable content:// URI exercises it — which is what kept #225 headless.
And that is how the read's one production defect surfaced
#238: joining files picked through the system picker failed outright on the stream-copy path. The concat demuxer whitelists protocols separately from -safe 0, and ffkitsaf was not on the list. Only STREAM_COPY feeds the demuxer a list file, and every existing join test passed Uri.fromFile — so the one broken combination was the only one a user could reach.
Worth stating plainly next to the coverage entry: it was not a missed line and not an unasserted value, but two covered things no test put together — the gap shape a coverage number is worst at, and the reason the read happened.
Also
The ticket table gains an outcome column: eight filed, seven closed, #226 open and re-scoped.
E4 marked fixed — #243 made that KDoc name FAILS_ON_EMULATOR_API37_BASELINE rather than restate it, so it cannot drift again.
Documentation only. Two results from #223–#230 that belong with the read rather than only in their own tickets, plus the outcome column for the ticket table.
## E7 — a real `DocumentsProvider` cannot be reached without the picker
#226 split into a cheap headless half and an expensive picker-driven one, on the premise that a real `DocumentsProvider` can be reached without DocumentsUI. **It cannot** — measured three ways on API 34:
| approach | result |
|---|---|
| a `DOCUMENTS_PROVIDER` without `MANAGE_DOCUMENTS` | refused at install: *"Provider must be protected by MANAGE_DOCUMENTS"* |
| create as the **test APK**, which owns the provider | denied — instrumentation runs in the *target app's* process, so it carries the app's uid |
| `adoptShellPermissionIdentity(MANAGE_DOCUMENTS)` | denied identically |
Each denial names the only way in: *"you obtain access using ACTION_OPEN_DOCUMENT or related APIs"*. And the intent filter is not optional — without it `isDocumentUri` returns false, which is exactly the branch guarding `deletePartialOutput`.
**So #226 is one item at the picker's cost, not two.** The ticket was updated to say so.
The useful half of the distinction: the **input** bridge needs no documents provider at all. `getSafParameterForRead` opens a descriptor through the resolver, so any readable `content://` URI exercises it — which is what kept #225 headless.
## And that is how the read's one production defect surfaced
**#238**: joining files picked through the system picker failed outright on the stream-copy path. The concat demuxer whitelists protocols separately from `-safe 0`, and `ffkitsaf` was not on the list. Only `STREAM_COPY` feeds the demuxer a list file, and every existing join test passed `Uri.fromFile` — so **the one broken combination was the only one a user could reach**.
Worth stating plainly next to the coverage entry: it was not a missed line and not an unasserted value, but *two covered things no test put together* — the gap shape a coverage number is worst at, and the reason the read happened.
## Also
- The ticket table gains an outcome column: eight filed, seven closed, #226 open and re-scoped.
- **E4 marked fixed** — #243 made that KDoc name `FAILS_ON_EMULATOR_API37_BASELINE` rather than restate it, so it cannot drift again.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Documentation only. Two results from #223–#230 that belong with the read rather than only in their own tickets, plus the outcome column for the ticket table.
E7 — a real
DocumentsProvidercannot be reached without the picker#226 split into a cheap headless half and an expensive picker-driven one, on the premise that a real
DocumentsProvidercan be reached without DocumentsUI. It cannot — measured three ways on API 34:DOCUMENTS_PROVIDERwithoutMANAGE_DOCUMENTSadoptShellPermissionIdentity(MANAGE_DOCUMENTS)Each denial names the only way in: "you obtain access using ACTION_OPEN_DOCUMENT or related APIs". And the intent filter is not optional — without it
isDocumentUrireturns false, which is exactly the branch guardingdeletePartialOutput.So #226 is one item at the picker's cost, not two. The ticket was updated to say so.
The useful half of the distinction: the input bridge needs no documents provider at all.
getSafParameterForReadopens a descriptor through the resolver, so any readablecontent://URI exercises it — which is what kept #225 headless.And that is how the read's one production defect surfaced
#238: joining files picked through the system picker failed outright on the stream-copy path. The concat demuxer whitelists protocols separately from
-safe 0, andffkitsafwas not on the list. OnlySTREAM_COPYfeeds the demuxer a list file, and every existing join test passedUri.fromFile— so the one broken combination was the only one a user could reach.Worth stating plainly next to the coverage entry: it was not a missed line and not an unasserted value, but two covered things no test put together — the gap shape a coverage number is worst at, and the reason the read happened.
Also
FAILS_ON_EMULATOR_API37_BASELINErather than restate it, so it cannot drift again.🤖 Generated with Claude Code