97

I have extracted image uri, now I would like to open image with Android's default image viewer. Or even better, user could choose what program to use to open the image. Something like File Explorers offer you if you try to open a file.

Morgoth
  • 4,935
  • 8
  • 40
  • 66
Badr Hari
  • 8,114
  • 18
  • 67
  • 100

14 Answers14

180

Accepted answer was not working for me,

What had worked:

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + "/sdcard/test.jpg"), "image/*");
startActivity(intent);
Vikas
  • 24,082
  • 37
  • 117
  • 159
  • 4
    yes but how do you avvoid on android 2.2 and 2.3 that 10 seconds black screen waiting while gallery says it searches for new fotos and albums? – max4ever May 30 '12 at 18:08
  • @max4ever : Have found solution to you problem ? – Code_Life Oct 08 '12 at 05:15
  • 4
    yes, `File f = new File(..., ...); if (f.isFile()) { MediaScannerConnection.scanFile(SchedaActivity.this, new String[] { f.toString() }, null, new MediaScannerConnection.OnScanCompletedListener() { @Override public void onScanCompleted(String path, Uri uri) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(uri, "image/*"); SchedaActivity.this.startActivityForResult(intent, SchedaActivity.this.ACTIVITY_CODE); } });` – max4ever Oct 09 '12 at 08:20
  • 1
    Android 4.1 will show you image if you only specify "image/*". This will not work on Android 2.3. You MUST specify the mime type: "image/jpeg". – Johann Jul 25 '13 at 17:30
  • On Android 2.3, if the file doesn't have an extension, even specifying the mime type with jpeg will not work. Oddly, Gallery viewer will ignore the file and just pick anyone in its folder. That's bad. – Johann Jul 25 '13 at 17:31
  • 7
    This answer ends up with `file:///sdcard...` - is that intentional? – Danyal Aytekin Mar 04 '14 at 17:14
  • Note: you may have to put `context` before `startActivity(intent)`. –  Mar 31 '14 at 14:31
  • Bit late but @DanyalAytekin yes, that is intentional. It's protocol:// and /sdcard means / for root, as in the first directory of the entire system followed by sdcard, which points to the file associated with the actual sdcard. If you search for UNIX file structures and look at linux's file structure, things should become clearer. – G_V Nov 18 '14 at 14:06
  • The drawback for using the default Gallery as image viewer instead of creating an new dedicated activity for that in your application, is that in the default gallery there is no back button from the action bar to your previous activity. You'll have to rely on the back buttons of the device that AFAIK doesn't exist in all new Android devices. I am right here? – GyRo Feb 19 '15 at 09:10
  • What will be the URI, if image is in res/raw or assests folder? I am getting, no application can perform this action while used with Intent.createChooser(). – Bharat Dodeja Aug 19 '16 at 10:14
  • This shows only single selected image and not other images in the same folder (so that user can swipe left/right to see other images). Any idea how to achieve this? – Atul Nov 23 '16 at 13:57
  • This solution throws a 'FileUriExposedException' on newer android version. However the solution of @android-developer – Petterson May 24 '19 at 10:03
41

If your app targets Android N (7.0) and above, you should not use the answers above (of the "Uri.fromFile" method), because it won't work for you.

Instead, you should use a ContentProvider.

For example, if your image file is in external folder, you can use this (similar to the code I've made here) :

File file = ...;
final Intent intent = new Intent(Intent.ACTION_VIEW)//
                                    .setDataAndType(VERSION.SDK_INT >= VERSION_CODES.N ?
                                                    FileProvider.getUriForFile(this,getPackageName() + ".provider", file) : Uri.fromFile(file),
                            "image/*").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

manifest:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

res/xml/provider_paths.xml :

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!--<external-path name="external_files" path="."/>-->
    <external-path
        name="files_root"
        path="Android/data/${applicationId}"/>
    <external-path
        name="external_storage_root"
        path="."/>
</paths>

If your image is in the private path of the app, you should create your own ContentProvider, as I've created "OpenFileProvider" on the link.

android developer
  • 114,585
  • 152
  • 739
  • 1,270
34

Ask myself, answer myself also:

startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("content://media/external/images/media/16"))); /** replace with your own uri */

It will also ask what program to use to view the file.

Badr Hari
  • 8,114
  • 18
  • 67
  • 100
  • 2
    Hi hari, your code is useful for opening image. Can you have a solution to open folder of gallery. here is my question http://stackoverflow.com/questions/6519024/access-specific-folder-of-gallery-in-android – djk Jun 30 '11 at 06:34
  • @djk I just answer this quest here http://stackoverflow.com/questions/6074270/built-in-gallery-in-specific-folder/8255674#8255674 see if it relate to your question. – PiyushMishra Nov 24 '11 at 10:57
  • Just in case someone else gets stuck on the same problem as me - I added intent.setType("image/png") (I knew the image would be a png file) and it prevented the gallery from opening the image! So .setType is counter-productive here :) – Daniel Apr 05 '13 at 19:13
  • Additionally, you can use `intent.setDataAndType(uri, "image/*");` to force Android to use an image viewing app. – Diego Stiehl Nov 17 '14 at 19:11
  • Can this method be used to avoid creating a new layout just to view image? – Marek Oct 18 '15 at 11:52
21

Try use it:

Uri uri =  Uri.fromFile(entry);
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
String mime = "*/*";
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
if (mimeTypeMap.hasExtension(
    mimeTypeMap.getFileExtensionFromUrl(uri.toString())))
    mime = mimeTypeMap.getMimeTypeFromExtension(
        mimeTypeMap.getFileExtensionFromUrl(uri.toString()));
intent.setDataAndType(uri,mime);
startActivity(intent);
Eugene
  • 211
  • 2
  • 3
  • This is perfect! It opens up popup/layout based on android os, so that user can select player or viewer based on user choice. example, to show image, music, video, app or even any file. – Pratik Saluja Dec 06 '16 at 15:49
  • I got " exposed beyond app through Intent.getData()" error. – Ramiz Ansari Jan 22 '19 at 18:34
  • If you are getting " exposed beyond app through Intent.getData()" error you can check this link to solve the problem https://stackoverflow.com/a/45751453/10619147 – Wojuola Ayotola Mar 10 '20 at 16:05
18

Based on Vikas answer but with a slight modification: The Uri is received by parameter:

private void showPhoto(Uri photoUri){
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_VIEW);
    intent.setDataAndType(photoUri, "image/*");
    startActivity(intent);
}
Community
  • 1
  • 1
Joaquin Iurchuk
  • 5,499
  • 2
  • 48
  • 64
  • 1
    This shows only single selected image and not other images in the same folder (so that user can swipe left/right to see other images). Any idea how to achieve this? – Atul Nov 23 '16 at 13:58
  • @Atul in that case the use case is completely different. OP wants to display an X image using its URI. It seems that you want to a) Open the gallery in determined position or b) Open in the gallery a subset of photos of which you have the URIs. Do some research on the web or ask a new question, as your use case is completely different. – Joaquin Iurchuk Nov 23 '16 at 14:05
  • Thanks for your quick reply. I need to achieve same what OP has asked. Your (and Vikas's) answer achieves it very well, Only thing is, once it shows image it doesn't allow to scroll through other images in same folder (when user swipes left or right). I've seen many apps (e.g. WhatsApp) show image in gallery viewer (just like what you do) but they also allow user to scroll through left right images in same folder. – Atul Nov 23 '16 at 14:12
  • @Atul OP wants to open _one_ image with Gallery given its URI. WhatsApp implementation is completely different. I don't know if Gallery supports receiving an Intent with many URIs. Anyway, [check out this,](https://code.tutsplus.com/tutorials/android-sdk-displaying-images-with-an-enhanced-gallery--mobile-11130) it might help you. – Joaquin Iurchuk Nov 23 '16 at 14:18
  • I already had seen the link you given. Thanks anyways. But I found someone has already [posted a question](http://stackoverflow.com/q/34838866/1911652) on what I want. However, his answer is too brief to understand. – Atul Nov 23 '16 at 14:25
12

This thing might help if your working with android N and below

 File file=new File(Environment.getExternalStorageDirectory()+"/directoryname/"+filename);
        Uri path= FileProvider.getUriForFile(MainActivity.this,BuildConfig.APPLICATION_ID + ".provider",file);

        Intent intent=new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(path,"image/*");
        intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION); //must for reading data from directory
A P
  • 2,131
  • 2
  • 24
  • 36
baswaraj
  • 629
  • 7
  • 7
  • FLAG_GRANT_READ_URI_PERMISSION helped for viewing image using Intent.ACTION_VIEW – Pavan Nov 24 '18 at 12:59
  • Worked for me. Just remember if you are using "intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);" then you have to add "intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);" after that.. Thanks for the awesome solution. – snehal agrawal May 14 '19 at 11:27
6

A much cleaner, safer answer to this problem (you really shouldn't hard code Strings):

public void openInGallery(String imageId) {
  Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendPath(imageId).build();
  Intent intent = new Intent(Intent.ACTION_VIEW, uri);
  startActivity(intent);
}

All you have to do is append the image id to the end of the path for the EXTERNAL_CONTENT_URI. Then launch an Intent with the View action, and the Uri.

The image id comes from querying the content resolver.

Christopher Perry
  • 38,891
  • 43
  • 145
  • 187
4

All the above answers not opening image.. when second time I try to open it show the gallery not image.

I got solution from mix of various SO answers..

Intent galleryIntent = new Intent(Intent.ACTION_VIEW, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
galleryIntent.setDataAndType(Uri.fromFile(mImsgeFileName), "image/*");
galleryIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(galleryIntent);

This one only worked for me..

Ranjithkumar
  • 16,071
  • 12
  • 120
  • 159
4

The problem with showing a file using Intent.ACTION_VIEW, is that if you pass the Uri parsing the path. Doesn't work in all cases. To fix that problem, you need to use:

Uri.fromFile(new File(filePath));

Instead of:

Uri.parse(filePath);

Edit

Here is my complete code:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(mediaFile.filePath)), mediaFile.getExtension());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Info

MediaFile is my domain class to wrap files from database in objects. MediaFile.getExtension() returns a String with Mimetype for the file extension. Example: "image/png"


Aditional code: needed for showing any file (extension)

import android.webkit.MimeTypeMap;

public String getExtension () {
    MimeTypeMap myMime = MimeTypeMap.getSingleton();
    return myMime.getMimeTypeFromExtension(MediaFile.fileExtension(filePath));
}

public static String fileExtension(String path) {
    if (path.indexOf("?") > -1) {
        path = path.substring(0, path.indexOf("?"));
    }
    if (path.lastIndexOf(".") == -1) {
        return null;
    } else {
        String ext = path.substring(path.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();
    }
}

Let me know if you need more code.

IgniteCoders
  • 4,834
  • 3
  • 44
  • 62
3

I use this it works for me

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), 1);
Muhammad Aamir Ali
  • 20,419
  • 10
  • 66
  • 57
2

My solution using File Provider

    private void viewGallery(File file) {

 Uri mImageCaptureUri = FileProvider.getUriForFile(
  mContext,
  mContext.getApplicationContext()
  .getPackageName() + ".provider", file);

 Intent view = new Intent();
 view.setAction(Intent.ACTION_VIEW);
 view.setData(mImageCaptureUri);
 List < ResolveInfo > resInfoList =
  mContext.getPackageManager()
  .queryIntentActivities(view, PackageManager.MATCH_DEFAULT_ONLY);
 for (ResolveInfo resolveInfo: resInfoList) {
  String packageName = resolveInfo.activityInfo.packageName;
  mContext.grantUriPermission(packageName, mImageCaptureUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
 }
 view.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
 Intent intent = new Intent();
 intent.setAction(Intent.ACTION_VIEW);
 intent.setDataAndType(mImageCaptureUri, "image/*");
 mContext.startActivity(intent);
}
creativecoder
  • 1,470
  • 1
  • 14
  • 23
0

Almost NO chance to use photo or gallery application(might exist one), but you can try the content-viewer.

Please checkout another answer to similar question here

Community
  • 1
  • 1
TeeTracker
  • 7,064
  • 8
  • 40
  • 46
0

My solution

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath()+"/your_app_folder/"+"your_picture_saved_name"+".png")), "image/*");
context.startActivity(intent);
knightcube
  • 139
  • 1
  • 13
0

The uri must be content uri not file uri, You can get contentUri by FileProvider as

Uri contentUri = FileProvider.getUriForFile(getContext(),"com.github.myApp",curFile);

Don't forget adding provider in Manifest file.

<provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="com.github.myApp"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
</provider>
Ahmet B.
  • 1,290
  • 10
  • 20