Multiple MIME types in Android
Asked Answered
F

8

90

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.

Freitag answered 8/11, 2009 at 21:52 Comment(2)
Could you be more specific. setType() on...what? For what use and purpose? Etc.Ahders
Have you found out a way to do this yet?Retortion
G
142

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);
Greg answered 2/5, 2014 at 11:11 Comment(8)
This doesn't work in Android 7.0. Only shows videos.Soy
@Soy It seems to work fine on my Nexus 9 with Android 7.0.Vampire
@Soy Seems to work fine on Android 7.0 emulator as well. Is there a specific case that doesn't work? It seems like this is the right answer since it is part of the official API.Vampire
Work perfectly. The Android way of filtering files types.Castalia
Note that EXTRA_MIME_TYPES doesn't replace setType. You still need setType with this approach.Atavistic
How do you do this for Jellybean and bellow?Intercession
Made my day. tksLyns
It doesn't work when we share content from app to another appsStultify
L
25

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.

Lozada answered 25/7, 2013 at 19:39 Comment(3)
This solution is working... but only with applications that allows two mime-types. The default one "Gallery" doesn't.Merbromin
Actually, it depends on the "Gallery" application you have installed. There are different versions of them being distributed with different android ROMs.Lozada
Works for me in minor cases only. Same images may or may not be selectable. Android 5.0.1Algetic
D
4

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.

Driscoll answered 18/5, 2012 at 2:34 Comment(4)
Actually, multiple mime-types are supported. Have you even tried it??? For example: image/*,video/* will display photos and videos...Lozada
@vchelbanster Multiple mimetypes are not supported in all devices. With some android version like < 5.0, it would pick only first mimetype.Audiology
@ShivamPokhriyal Partially agree - it's not available for all the apps. Since the app that gets a composite intent type needs to handle multiple mime types for this to work, not all the apps (like gallery app) will work, which might create the impression that it's the OS version that's dependent on. In fact, it's the app's creator that need to handle multiple mime types. So yeah - it's limited support. See my answer.Lozada
@vchelbanster Yup, at first it appeared to me that this is related to OS version. Later I figured out that if your device doesn't have app that handles such type of intents, then the problem will occur.Audiology
M
2

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.

Messing answered 7/4, 2015 at 16:56 Comment(0)
G
1

you can pass multiple mime types if you separate with |

Intent.setType("application/*|text/*");
Granular answered 2/9, 2014 at 12:16 Comment(0)
E
0

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
        }
    }
}

Echovirus answered 17/11, 2023 at 13:49 Comment(0)
R
0

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:

  • Xiaomi File Manager
  • FileManager+
  • ZArchiver
  • Total Commander

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)
Randle answered 7/6 at 12:50 Comment(0)
F
-3

for my work with semicolons.

Example:

intent.setType("image/*;video/*")

or

sIntent.putExtra("CONTENT_TYPE", "image/*;video/*"); 
Fact answered 4/3, 2014 at 16:38 Comment(1)
Instead of the hard-coded "CONTENT_TYPE" string you can use the Intent.EXTRA_MIME_TYPES constant. Also instead of semicolons, you can pass an array of strings.Greg

© 2022 - 2024 — McMap. All rights reserved.