The GetContent
contract only takes a single String
argument, which can only contain a single MIME type.
The OpenDocument
contract takes an array of String
, each a single MIME type.
There are pros and cons to each so see this StackOverflow question to help you decide which to use. I have no idea why it was decided to limit GetContact
to a single MIME type.
lglink's answer shows one way to get multi-MIME GetContent
by extending that contract with a ;
-delimited String
of concatenated MIME types.
I solved it another way, by following the official docs to make a custom contract:
class BespokeContract: ActivityResultContract<Array<String>, Uri?>() {
@CallSuper
override fun createIntent(context: Context, input: Array<String>): Intent {
return Intent(Intent.ACTION_GET_CONTENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType("*/*")
.putExtra(Intent.EXTRA_MIME_TYPES, input)
}
override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
return intent.takeIf { resultCode == Activity.RESULT_OK }?.data
}
}
As a newcomer to Android programming, I struggled a lot to get this. There were a few things those docs didn't mention without which my code was not working. Perhaps they are common knowledge amongst experienced Android devs, but for anyone jumping in in 2023, not so much. I ended up having to look at the Android source for GetContent
:
- A
GetContent
contract uses the ACTION_GET_CONTENT
Intent:
Intent(Intent.ACTION_GET_CONTENT)
- If you're making a new contract rather than extending an existing one, you need to add the
OPENABLE
category. You'll get a confusing error if you don't:
.addCategory(Intent.CATEGORY_OPENABLE)
- Before you put extra mime types you must first use
setType()
, even though what you put there will be ignored. */*
is commonly seen and is perhaps the shortest. Again you'll get a confusing error if you don't:
.setType("*/*")
- And of course the main part:
.putExtra(Intent.EXTRA_MIME_TYPES, input)
For anyone confused like I was by seeing many ways of doing this when searching the internet for help and not knowing which are deprecated and which are due to old Views code vs new Compose code, etc, this is an equivalent different way to code createIntent
:
override fun createIntent(context: Context, input: Array<String>) =
Intent(Intent.ACTION_GET_CONTENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
putExtra(Intent.EXTRA_MIME_TYPES, input)
}