69

My app has a feature that browse files on your phone and SD card and open them using other apps. I want a solution where I don't have to specify the MimeType and can work with any type of file.

Here is my code:

Intent myIntent = new Intent(Intent.ACTION_VIEW);
myIntent.setData(Uri.fromFile(item));
startActivity(myIntent);

However, I'm getting the following error:

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.PICK dat=file:///sdcard/dropbox/test.pdf }
Volo
  • 28,673
  • 12
  • 97
  • 125
dannyroa
  • 5,501
  • 6
  • 41
  • 59

13 Answers13

125

This should detect the mimetype and open with default:

MimeTypeMap myMime = MimeTypeMap.getSingleton();
Intent newIntent = new Intent(Intent.ACTION_VIEW);
String mimeType = myMime.getMimeTypeFromExtension(fileExt(getFile()).substring(1));
newIntent.setDataAndType(Uri.fromFile(getFile()),mimeType);
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
    context.startActivity(newIntent);
} catch (ActivityNotFoundException e) {
    Toast.makeText(context, "No handler for this type of file.", Toast.LENGTH_LONG).show();
}

Using this function:

private String fileExt(String url) {
    if (url.indexOf("?") > -1) {
        url = url.substring(0, url.indexOf("?"));
    }
    if (url.lastIndexOf(".") == -1) {
        return null;
    } else {
        String ext = url.substring(url.lastIndexOf(".") + 1);
        if (ext.indexOf("%") > -1) {
            ext = ext.substring(0, ext.indexOf("%"));
        }
        if (ext.indexOf("/") > -1) {
            ext = ext.substring(0, ext.indexOf("/"));
        }
        return ext.toLowerCase();

    }
}
howettl
  • 12,419
  • 13
  • 56
  • 91
NoBugs
  • 9,310
  • 13
  • 80
  • 146
  • 11
    How about [URLConnection.guessContentTypeFromName(url)](http://developer.android.com/reference/java/net/URLConnection.html#guessContentTypeFromName(java.lang.String))? – Robert Siemer May 09 '13 at 15:19
  • 5
    There is a problem with this code: in third line of code you shouldn't use substring(1). use this line: `String mimeType = myMime.getMimeTypeFromExtension(fileExt(getFile()));`. (fileExt will only return the extension without dot.) – Moradnejad Jul 18 '16 at 10:25
  • 2
    User FileProvider instead of URI.fromFile() on target >= 24 androids – nAkhmedov May 02 '18 at 12:46
18

createChooser should do the trick:

Intent myIntent = new Intent(Intent.ACTION_VIEW);
myIntent.setData(Uri.fromFile(item));
Intent j = Intent.createChooser(myIntent, "Choose an application to open with:");
startActivity(j);
BadSkillz
  • 1,993
  • 19
  • 37
16

try this one almost covers all file extensions

  public void openFile(File url) {

    Uri uri = Uri.fromFile(url);

    Intent intent = new Intent(Intent.ACTION_VIEW);
    if (url.toString().contains(".doc") || url.toString().contains(".docx")) {
        // Word document
        intent.setDataAndType(uri, "application/msword");
    } else if (url.toString().contains(".pdf")) {
        // PDF file
        intent.setDataAndType(uri, "application/pdf");
    } else if (url.toString().contains(".ppt") || url.toString().contains(".pptx")) {
        // Powerpoint file
        intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
    } else if (url.toString().contains(".xls") || url.toString().contains(".xlsx")) {
        // Excel file
        intent.setDataAndType(uri, "application/vnd.ms-excel");
    } else if (url.toString().contains(".zip") || url.toString().contains(".rar")) {
        // WAV audio file
        intent.setDataAndType(uri, "application/x-wav");
    } else if (url.toString().contains(".rtf")) {
        // RTF file
        intent.setDataAndType(uri, "application/rtf");
    } else if (url.toString().contains(".wav") || url.toString().contains(".mp3")) {
        // WAV audio file
        intent.setDataAndType(uri, "audio/x-wav");
    } else if (url.toString().contains(".gif")) {
        // GIF file
        intent.setDataAndType(uri, "image/gif");
    } else if (url.toString().contains(".jpg") || url.toString().contains(".jpeg") || url.toString().contains(".png")) {
        // JPG file
        intent.setDataAndType(uri, "image/jpeg");
    } else if (url.toString().contains(".txt")) {
        // Text file
        intent.setDataAndType(uri, "text/plain");
    } else if (url.toString().contains(".3gp") || url.toString().contains(".mpg") || url.toString().contains(".mpeg") || url.toString().contains(".mpe") || url.toString().contains(".mp4") || url.toString().contains(".avi")) {
        // Video files
        intent.setDataAndType(uri, "video/*");
    } else {
        //if you want you can also define the intent type for any other file
        //additionally use else clause below, to manage other unknown extensions
        //in this case, Android will show all applications installed on the device
        //so you can choose which application to use
        intent.setDataAndType(uri, "*/*");
    }

    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(intent);

}
Ameen Maheen
  • 2,719
  • 1
  • 28
  • 28
8
Intent myIntent = new Intent(Intent.ACTION_VIEW);
String mime=URLConnection.guessContentTypeFromStream(new FileInputStream(item));
if(mime==null) mime=URLConnection.guessContentTypeFromName(item.getName());
myIntent.setDataAndType(Uri.fromFile(item), mime);
startActivity(myIntent);

At first I try to guess with the file content, but as i see it always returns null.

sercxjo
  • 328
  • 2
  • 12
  • 1
    [Doesn't work when targeting Android N](http://stackoverflow.com/q/38200282/4583267) – Thomas Vos Jul 08 '16 at 11:31
  • 1
    Thomas Vos's point is crucial. This code is useful but if you're going to use it then you need to set your targetSdkVersion to 23 or under. If an Android 7.0 device runs this code it will crash. – CKP78 Nov 22 '17 at 17:54
5

You can find out the mime type of a file and make your own intent to open the file.

Use the following code to open any file...

File temp_file=new File("YOUR FILE PATH");
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(temp_file),getMimeType(temp_file.getAbsolutePath()));
startActivity(intent); 

Where getMimeType() is....(this method will return desired mime type or null if the file does not have any proper mime type)...

private String getMimeType(String url)
    {
        String parts[]=url.split("\\.");
        String extension=parts[parts.length-1];
        String type = null;
        if (extension != null) {
            MimeTypeMap mime = MimeTypeMap.getSingleton();
            type = mime.getMimeTypeFromExtension(extension);
        }
        return type;
    }
Tamal Samui
  • 738
  • 10
  • 14
5

Android does not start activities based on file extensions, unless there's an app that specifies a particular intent filter for it. You will need the mime type to the Intent to tell android enough information to start the right Activity.

You have the option to automate this task by using the MimeTypeMap class. Check the method String getMimeTypeFromExtension(String extension).

BTW, do you have a pdf reader installed in your device?

You should also handle this exception, probably by showing a nice popup saying that there is no app for that particular type of file.

Aleadam
  • 40,203
  • 9
  • 86
  • 108
2

Simple share file ("multipart/")

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
intent.setType("multipart/");
startActivity(intent);
ChangUZ
  • 5,380
  • 10
  • 46
  • 64
2

This will work surely..

 private void showFile(File file, String filetype) 
{
                MimeTypeMap myMime = MimeTypeMap.getSingleton();
                Intent intent = new Intent(Intent.ACTION_VIEW);
                String mimeType = 
                myMime.getMimeTypeFromExtension(filetype);
                if(android.os.Build.VERSION.SDK_INT >=24) {
                 Uri fileURI = FileProvider.getUriForFile(getContext(),
                            BuildConfig.APPLICATION_ID + ".provider",
                            file);
                    intent.setDataAndType(fileURI, mimeType);

                }else {
                    intent.setDataAndType(Uri.fromFile(file), mimeType);
                }
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_GRANT_READ_URI_PERMISSION);
                try {
                    context.startActivity(intent);
                }catch (ActivityNotFoundException e){
                    Toast.makeText(context, "No Application found to open this type of file.", Toast.LENGTH_LONG).show();

                }
            }
avinash
  • 29
  • 4
1

I wrote these few lines in kotlin and and it works like a charm.Enjoy it.

val file = File(path)              
val mimeType = URLConnection.guessContentTypeFromName(file.absolutePath)
                Intent().apply {
                    setDataAndType(Uri.fromFile(file), mimeType)
                    flags = Intent.FLAG_ACTIVITY_NEW_TASK
                }.let {
                    try {
                        itemView.context.startActivity(it)
                    } catch (e: ActivityNotFoundException) {
                        Toast.makeText(itemView.context, "There's no program to open this file", Toast.LENGTH_LONG).show()
                    }
                }
Steve Moretz
  • 2,758
  • 1
  • 17
  • 31
0

There is a problem with NoBugs's answer. This is directly out of the eclipse function information window:

String android.webkit.MimeTypeMap.getMimeTypeFromExtension(String extension)

public String getMimeTypeFromExtension (String extension)

Since: API Level 1

Return the MIME type for the given extension.

Parameters

extension A file extension without the leading '.'

Returns The MIME type for the given extension or null iff there is none.

Timberwolf
  • 426
  • 4
  • 13
0

Use this method to get the MIME type from the uri of the file :

public static String getMimeType(String url) {

    String type = null;
    String extension = url.substring(url.lastIndexOf(".") + 1);
    if (extension != null) {
        type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    }
    return type;
}
Amr El Aswar
  • 3,395
  • 3
  • 23
  • 36
0

You should always check the same with

PackageManager packageManager = getActivity().getPackageManager();
if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent);
} else {
    Log.d(TAG, "No Intent available to handle action");

}

and to get MimeTpye of file you can use :-

 public String getMimeType(Uri uri, Context context) {
        String mimeType = null;
        if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
            ContentResolver cr = context.getContentResolver();
            mimeType = cr.getType(uri);
        } else {
            String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
                    .toString());
            mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
                    fileExtension.toLowerCase());
        }
        return mimeType;
    }
Balwinder SIngh
  • 1,831
  • 2
  • 24
  • 28
0

You have to use the MimeTypeMap and get the type using the file extension. Then pass it to intent to open any type of file.

Kotlin

fun getIntentForFile(filePath: String, context: Context): Intent {
    val intent = Intent()

    val uri = FileProvider.getUriForFile(
        context,
        context.applicationContext.packageName + ".fileprovider",
        File(filePath)
    )
    intent.action = Intent.ACTION_VIEW
    intent.putExtra(Intent.EXTRA_STREAM, uri)
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    intent.setDataAndType(uri, getFileContentType(filePath))
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    return intent
}

fun getFileContentType(filePath: String): String? {
    val file = File(filePath)
    val map = MimeTypeMap.getSingleton()
    val ext = MimeTypeMap.getFileExtensionFromUrl(file.name)
    var type = map.getMimeTypeFromExtension(ext)
    if (type == null) type = "*/*"
    return type
}
Sreekant Shenoy
  • 1,420
  • 14
  • 23