Is there a way to use intent.setType()
and supply multiple broad types (like images and video)?
I am using an ACTION_GET_CONTENT
. It seems to be working with just comma-separated types.
Is there a way to use intent.setType()
and supply multiple broad types (like images and video)?
I am using an ACTION_GET_CONTENT
. It seems to be working with just comma-separated types.
In Android 4.4 when using the Storage Access Framework you can use the EXTRA_MIME_TYPES
to pass multiple mime types.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
String[] mimetypes = {"image/*", "video/*"};
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
startActivityForResult(intent, REQUEST_CODE_OPEN);
EXTRA_MIME_TYPES
doesn't replace setType
. You still need setType
with this approach. –
Atavistic Actually, multiple mime-types are supported. Have you even tried it???
For example: intent.setType("image/*,video/*")
will display photos and videos...
For me it works. It should work for you too...
[EDIT]: This works partially, as not all the gallery apps choose to implement support for multiple mime types filters.
Sorry, this is not currently supported. You have two options:
(1) Use a MIME type of */*
and accept that there may be some things the user can pick that you won't be able to handle (and have a decent recovery path for that); or
(2) Implement your own activity chooser, doing direct calls on the package manager to get the activities that can handle both MIME types for the intent, merging those lists, and displaying them to the user.
Also, setType()
does not work with comma-separated types at all. It must be one and only one MIME type.
For me what worked best was:
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
You can add several mime types like this
intent.setType("image/*|application/pdf|audio/*");
But the intent chooser will only display applications that can handle images because it is the first in the mime type string.
However if you have a file manager installed (I tested with the CyanogenMod file manager) you can choose a file that is audio or pdf or an image.
If the audio mime type is the first one, like this:
intent.setType("audio/*|image/*|application/pdf");
The intent chooser will display only applications that handle audio.
Again using the file manager you can select an image or pdf or audio.
you can pass multiple mime types if you separate with |
Intent.setType("application/*|text/*");
With registerForActivityResult()
callback:
import androidx.activity.result.contract.ActivityResultContracts
class DocumentsFragment : Fragment() {
companion object {
// 1. List of MIME types
/**@see <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types">MIME types</a>
* @see <a href="https://www.iana.org/assignments/media-types/media-types.xhtml">IANA - MIME types</a>*/
private val MIME_TYPES: Array<String> = arrayOf(
"image/*", "application/pdf", "application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.oasis.opendocument.text", "text/plain", "text/markdown"
)
}
//2. Register for Activity Result callback as class field
private val getDocuments =
registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()/*NOT OpenDocument*/) {
Log.d("Open documents", "incoming uri: size = ${it.size}")
add(it)
}
...
//3. set onclick listener
selectDocumentsButton.setOnClickListener { getDocuments.launch(MIME_TYPES) }
...
//4. handle incoming uri list
private fun add(list: List<Uri>) {
val setOfFiles = copyToAppDir(list)
setOfFiles.forEach {
//TODO: do something
}
}
//5. copy the files to the application folder for further work
private fun copyToAppDir(list: List<Uri>): Set<File> {
val set = mutableSetOf<File>()
list.forEach { uri ->
try {
val file: File = copyUriContentToTempFile(uri)
set.add(file)
} catch (e: Exception) {
e.printStackTrace()
}
}
return set
}
//6. copy selected content by uri
private fun copyUriContentToTempFile(uri: Uri): File {
val inputStream = requireContext().contentResolver.openInputStream(uri)
inputStream.use { input ->
val tempFile: File = .. ; //TODO: create file
tempFile.outputStream().use { output ->
input?.copyTo(output)
}
return tempFile
}
}
}
Had to implement file uploading to WebView which accepts multiple file MIME types. I managed to do it by creating custom ActivityResultContract
and setting extra to Intent Intent.EXTRA_MIME_TYPES
which seems to be working with default phone file manager and some other popular file managers like:
Implementation:
class MultipleMimeTypeGetContentContract : ActivityResultContract<Array<String>, Uri?>() {
override fun createIntent(context: Context, input: Array<String>) =
Intent(Intent.ACTION_GET_CONTENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
setType("*/*") // Required for multiple disjointed MIME types
putExtra(Intent.EXTRA_MIME_TYPES, input)
}
override fun parseResult(resultCode: Int, intent: Intent?) =
intent.takeIf { resultCode == Activity.RESULT_OK }?.data
}
Register contract in activity like so:
private val launcher = registerForActivityResult(MultipleMimeTypeGetContentContract()) {
// Handle result
}
Launch file chooser:
launcher.launch(acceptedTypes)
for my work with semicolons.
Example:
intent.setType("image/*;video/*")
or
sIntent.putExtra("CONTENT_TYPE", "image/*;video/*");
Intent.EXTRA_MIME_TYPES
constant. Also instead of semicolons, you can pass an array of strings. –
Greg © 2022 - 2024 — McMap. All rights reserved.