Get/pick an image from Android's built-in Gallery app programmatically

340,132

Solution 1

This is a complete solution. I've just updated this example code with the information provided in the answer below by @mad. Also check the solution below from @Khobaib explaining how to deal with picasa images.

Update

I've just reviewed my original answer and created a simple Android Studio project you can checkout from github and import directly on your system.

https://github.com/hanscappelle/SO-2169649

(note that the multiple file selection still needs work)

Single Picture Selection

With support for images from file explorers thanks to user mad.

public class BrowsePictureActivity extends Activity {

    // this is the action code we use in our intent, 
    // this way we know we're looking at the response from our own action
    private static final int SELECT_PICTURE = 1;

    private String selectedImagePath;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        findViewById(R.id.Button01)
                .setOnClickListener(new OnClickListener() {

                    public void onClick(View arg0) {

                        // in onCreate or any event where your want the user to
                        // select a file
                        Intent intent = new Intent();
                        intent.setType("image/*");
                        intent.setAction(Intent.ACTION_GET_CONTENT);
                        startActivityForResult(Intent.createChooser(intent,
                                "Select Picture"), SELECT_PICTURE);
                    }
                });
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            if (requestCode == SELECT_PICTURE) {
                Uri selectedImageUri = data.getData();
                selectedImagePath = getPath(selectedImageUri);
            }
        }
    }

    /**
     * helper to retrieve the path of an image URI
     */
    public String getPath(Uri uri) {
            // just some safety built in 
            if( uri == null ) {
                // TODO perform some logging or show user feedback
                return null;
            }
            // try to retrieve the image from the media store first
            // this will only work for images selected from gallery
            String[] projection = { MediaStore.Images.Media.DATA };
            Cursor cursor = managedQuery(uri, projection, null, null, null);
            if( cursor != null ){
                int column_index = cursor
                .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();
                String path = cursor.getString(column_index);
                cursor.close();
                return path;
            }
            // this is our fallback here
            return uri.getPath();
    }

}

Selecting Multiple Pictures

Since someone requested that information in a comment and it's better to have information gathered.

Set an extra parameter EXTRA_ALLOW_MULTIPLE on the intent:

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

And in the Result handling check for that parameter:

if (Intent.ACTION_SEND_MULTIPLE.equals(data.getAction()))
        && Intent.hasExtra(Intent.EXTRA_STREAM)) {
    // retrieve a collection of selected images
    ArrayList<Parcelable> list = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
    // iterate over these images
    if( list != null ) {
       for (Parcelable parcel : list) {
         Uri uri = (Uri) parcel;
         // TODO handle the images one by one here
       }
   }
} 

Note that this is only supported by API level 18+.

Solution 2

Here is an update to the fine code that hcpl posted. but this works with OI file manager, astro file manager AND the media gallery too (tested). so i guess it will work with every file manager (are there many others than those mentioned?). did some corrections to the code he wrote.

public class BrowsePicture extends Activity {

    //YOU CAN EDIT THIS TO WHATEVER YOU WANT
    private static final int SELECT_PICTURE = 1;

    private String selectedImagePath;
    //ADDED
    private String filemanagerstring;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ((Button) findViewById(R.id.Button01))
        .setOnClickListener(new OnClickListener() {

            public void onClick(View arg0) {

                // in onCreate or any event where your want the user to
                // select a file
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent,
                        "Select Picture"), SELECT_PICTURE);
            }
        });
    }

    //UPDATED
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            if (requestCode == SELECT_PICTURE) {
                Uri selectedImageUri = data.getData();

                //OI FILE Manager
                filemanagerstring = selectedImageUri.getPath();

                //MEDIA GALLERY
                selectedImagePath = getPath(selectedImageUri);

                //DEBUG PURPOSE - you can delete this if you want
                if(selectedImagePath!=null)
                    System.out.println(selectedImagePath);
                else System.out.println("selectedImagePath is null");
                if(filemanagerstring!=null)
                    System.out.println(filemanagerstring);
                else System.out.println("filemanagerstring is null");

                //NOW WE HAVE OUR WANTED STRING
                if(selectedImagePath!=null)
                    System.out.println("selectedImagePath is the right one for you!");
                else
                    System.out.println("filemanagerstring is the right one for you!");
            }
        }
    }

    //UPDATED!
    public String getPath(Uri uri) {
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = managedQuery(uri, projection, null, null, null);
        if(cursor!=null)
        {
            //HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
            //THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
            int column_index = cursor
            .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }
        else return null;
    }

Solution 3

hcpl's methods work perfectly pre-KitKat, but not working with the DocumentsProvider API. For that just simply follow the official Android tutorial for documentproviders: https://developer.android.com/guide/topics/providers/document-provider.html -> open a document, Bitmap section.

Simply I used hcpl's code and extended it: if the file with the retrieved path to the image throws exception I call this function:

private Bitmap getBitmapFromUri(Uri uri) throws IOException {
        ParcelFileDescriptor parcelFileDescriptor =
             getContentResolver().openFileDescriptor(uri, "r");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
        parcelFileDescriptor.close();
        return image;
}

Tested on Nexus 5.

Solution 4

I went through the solution from @hcpl & @mad. hcpl's solution supports well for local image in the gallery & mad provided a better solution on top of that - it helps to load OI/Astro/Dropbox image as well. But in my app, while working on picasa library that's now integrated in Android Gallery, both solution fail.

I searched & analyzed a bit & eventually have come with a better & elegant solution that overcomes this limitation. Thanks to Dimitar Darazhanski for his blog, that helped me in this case, I modified a bit to make it easier to understand. Here is my solution goes -

public class BrowsePicture extends Activity {

//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;

private String selectedImagePath;
//ADDED
private String filemanagerstring;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ((Button) findViewById(R.id.Button01))
    .setOnClickListener(new OnClickListener() {

        public void onClick(View arg0) {

            // in onCreate or any event where your want the user to
            // select a file
            Intent intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(intent,
                    "Select Picture"), SELECT_PICTURE);
        }
    });
}

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        if (requestCode == SELECT_PICTURE) {
            Uri selectedImageUri = data.getData();
            Log.d("URI VAL", "selectedImageUri = " + selectedImageUri.toString());
            selectedImagePath = getPath(selectedImageUri);

            if(selectedImagePath!=null){         
                // IF LOCAL IMAGE, NO MATTER IF ITS DIRECTLY FROM GALLERY (EXCEPT PICASSA ALBUM),
                // OR OI/ASTRO FILE MANAGER. EVEN DROPBOX IS SUPPORTED BY THIS BECAUSE DROPBOX DOWNLOAD THE IMAGE 
                // IN THIS FORM - file:///storage/emulated/0/Android/data/com.dropbox.android/...
                System.out.println("local image"); 
            }
            else{
                System.out.println("picasa image!");
                loadPicasaImageFromGallery(selectedImageUri);
            }
        }
    }
}


// NEW METHOD FOR PICASA IMAGE LOAD
private void loadPicasaImageFromGallery(final Uri uri) {
    String[] projection = {  MediaColumns.DATA, MediaColumns.DISPLAY_NAME };
    Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
    if(cursor != null) {
        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME);
        if (columnIndex != -1) {
            new Thread(new Runnable() {
                // NEW THREAD BECAUSE NETWORK REQUEST WILL BE MADE THAT WILL BE A LONG PROCESS & BLOCK UI
                // IF CALLED IN UI THREAD 
                public void run() {
                    try {
                        Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
                        // THIS IS THE BITMAP IMAGE WE ARE LOOKING FOR.
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }).start();
        }
    }
    cursor.close();
}


public String getPath(Uri uri) {
    String[] projection = {  MediaColumns.DATA};
    Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
    if(cursor != null) {
        //HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
        //THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
        cursor.moveToFirst();
        int columnIndex = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
        String filePath = cursor.getString(columnIndex);
        cursor.close();
        return filePath;
    }
    else 
        return uri.getPath();               // FOR OI/ASTRO/Dropbox etc
}

Check it & let me know if there's some issue with it. I have tested it & it works well in every case.

Hope this will help everyone.

Solution 5

basis with the above code, I reflected the code like below, may be it's more suitable:

public String getPath(Uri uri) {
    String selectedImagePath;
    //1:MEDIA GALLERY --- query from MediaStore.Images.Media.DATA
    String[] projection = { MediaStore.Images.Media.DATA };
    Cursor cursor = managedQuery(uri, projection, null, null, null);
    if(cursor != null){
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        selectedImagePath = cursor.getString(column_index);
    }else{
        selectedImagePath = null;
    }

    if(selectedImagePath == null){
        //2:OI FILE Manager --- call method: uri.getPath()
        selectedImagePath = uri.getPath();
    }
    return selectedImagePath;
}
Share:
340,132

Related videos on Youtube

Michael Kessler
Author by

Michael Kessler

I am a Software Development company owner and an independent Mobile developer. Mobile development: - iOS: Swift - Android: Kotlin - iOS: Objective-C - Android: Java

Updated on March 08, 2021

Comments

  • Michael Kessler
    Michael Kessler about 3 years

    I am trying to open an image / picture in the Gallery built-in app from inside my application.

    I have a URI of the picture (the picture is located on the SD card).

    Do you have any suggestions?

    • Anthony Forloney
      Anthony Forloney over 14 years
      I have updated my answer to provide more test code to ensure that you retrieve the results correctly.
    • mad
      mad over 13 years
      look at my answer, it is an update to hcpl's code and it works for astro file manager and oi file manager too.
    • Vikas
      Vikas almost 13 years
      Someone should update question, "Get/pick an image from Android's...". Current question interprets that I have image and I want to show it via default gallery app.
    • Michael Kessler
      Michael Kessler almost 13 years
      @Vikas, seems that you are right. I don't remember what exactly I have tried to accomplish more than a year ago and why all the answers (including the one that I have selected as a solution) actually answer to a different question...
    • Michael Kessler
      Michael Kessler almost 13 years
      Actually, I don't know if it is right to change the question completely. There are 36 people who have added the question to their favorites...
    • Takermania
      Takermania almost 9 years
      This question has been answered step by step in this tutorial [click to view Tutorial][1] [1]: stackoverflow.com/questions/30506301/…
  • Michael Kessler
    Michael Kessler over 14 years
    @Anthony, thank you for your response. Unfortunately it doesn't work for me. I get the next error: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.GET_CONTENT typ=file:///sdcard/images/* }
  • Anthony Forloney
    Anthony Forloney over 14 years
    You need to call startActivityforResult and supply an activity. That's what I was referring to about deciding on what to next, my bad.
  • Michael Kessler
    Michael Kessler over 14 years
    It still doesn't work... I check that the folder exists and that there is an image file inside the folder. I call startActivityForResult(intent, 1); and still get this error... This code is located outside the Activity, but I have a reference to the activity and call the startActivityForResult method on that reference - maybe this is the reason?
  • Anthony Forloney
    Anthony Forloney over 14 years
    Nah, shouldnt be the reason, what is 1 that your passing in? Try IMAGE_PICK
  • Michael Kessler
    Michael Kessler over 14 years
    The second param is just something for me, isn't it? This is just an int that will be passed back to me together with the result. Tried also the Intent.ACTION_PICK instead of Intent.ACTION_GET_CONTENT. What do you mean by IMAGE_PICK? There is no such a constant. I also tried intent.setData(Uri.fromFile(new File("/sdcard/image/")));. I tried all the possible combinations of these and nothing seems to work...
  • Anthony Forloney
    Anthony Forloney over 14 years
    yeah IMAGE_PICK was a personal constant for another person having problems with Android, I thought it was a constant that choose which image picked, but what happens when you tried to use intent.setData(...), do you get an error message? or nothing happens?
  • Michael Kessler
    Michael Kessler over 14 years
    I get an exception on startActivityForResult method call in all the cases (ACTION_GET_CONTENT, ACTION_PICK, setType, setData), tried to remove the "file://" prefix, tried to remove the "*" posfix, tried to remove both, tried to give the full path to the file - I've tried all the combinations. Notice that it opens the Gallery app when I don't mention the exact folder or file and use the setType("image/*");.
  • Michael Kessler
    Michael Kessler over 14 years
    Does it work for you? Have you tried it? If it does then what platform are you working on? I use the Android 1.5
  • Anthony Forloney
    Anthony Forloney over 14 years
    I have not tried it, so I couldn't say whether it would work or not and I am using the Android 2.0
  • Rohith Nandakumar
    Rohith Nandakumar over 13 years
    It doesn't work when I use Astro file manager. Any ideas why?
  • Vikas
    Vikas over 13 years
    How do I retrieve Bitmap image from OI path?
  • mad
    mad over 13 years
    look at the code. at the lines with the comment //NOW WE HAVE OUR WANTED STRING...this is all you need. then use BitmapFactory class to retrieve a bitmap from a path
  • hcpl
    hcpl almost 13 years
    Thanks! You have a good point, never tried other file managers :).
  • GeneCode
    GeneCode almost 13 years
    Hi thanks a lot for this. Im a noobie though, can anyone tell me how to use the selectedImagePath or the other paths and set the image in ImageView?
  • pgsandstrom
    pgsandstrom almost 13 years
    I would also like to close the cursor :)
  • ashughes
    ashughes over 12 years
    Could also change else return null; in getPath(Uri uri) to return uri.getPath(); and get rid of the first filemanagerstring = selectedImageUri.getPath(); check. This way you just make one call to getPath(Uri) and get the path back (no matter if it was the Gallery or a file manager that was used).
  • CQM
    CQM over 12 years
    onActivityResult is never called in my program :( I am using tabhosts and have tried putting the onActivityResult() method in my TabActivity, my TabGroup AND my original view Activity that originally called the gallery
  • Noby
    Noby over 12 years
    @hcpl Thank you for answer. Can you please tell me how to get multiple images...?
  • PiyushMishra
    PiyushMishra over 12 years
    @Michael kessler I just answer a question stackoverflow.com/questions/6074270/… if it help you in anyway.
  • Gabor
    Gabor over 12 years
    small addition for device compatibility: intent.setType("image/*"); if (android.os.Build.MODEL.startsWith("HTC")) intent.putExtra("folderType", "com.htc.HTCAlbum.ALL_PHOTOS");
  • Dave_P
    Dave_P over 12 years
    @hcpl... what if you wanted to drill down into the gallery to a specified directory programatically. If the app creates a directory that shows in the gallery, can you just take the user directly to that gallery? handling exceptions of course. I wouldnt want to show the user every directory and have them select, I just want to show them the directory that I want them to be in. You can email me if you want [email protected]
  • Mario
    Mario almost 12 years
    thx a lot. but if i choose gallery as source. it will still show the app choice after i select an image. if i choose the filemanager it works all great
  • gcl1
    gcl1 over 11 years
    I think "selectedImagePath = getPath(selectedImageUri);" should be "selectedImagePath = selectedImageUri.getPath();". Then, it compiled and worked for me.
  • Torben
    Torben over 11 years
    You did not understand the question before answering. Also, you did not include any description about what you try to do. Also, your code breaks some well established Java programming standards.
  • Khobaib
    Khobaib almost 11 years
    @hcpl I have provided a solution that supports picasa album's image loading also(picase album is part of Android gallery now). Check my solution.
  • Khobaib
    Khobaib almost 11 years
    @mad I have provided a solution that supports picasa album's image loading also(picase album is part of Android gallery now). Check my solution.
  • hcpl
    hcpl over 10 years
    @gcl1 the getPath() method is a custom helper, don't forget to add it to your code. It will use a content provider if possible and fall back on the uri.getPath() function if not.
  • hcpl
    hcpl over 10 years
    @Noby check my updated answer, it has some info on how to select multiple images on API level 18 and higher. Before that you'll have to provide your own media browser or look for an open source library.
  • hcpl
    hcpl over 10 years
    @Khobaib Thanks for the update. I've added a pointer in my answer.
  • Christopher Masser
    Christopher Masser over 10 years
    Getting a single picture doesn't seem to be working on the newest Android version 4.4 (KitKat) anymore. The _data column from the query returns a null value.
  • Snake
    Snake over 10 years
    @Chsristopher Masser, Any suggested alternative for Kitkat?
  • IgorGanapolsky
    IgorGanapolsky over 10 years
    Does one need to know the uri of the image here? What if I just want to pick an arbitrary image from the gallery?
  • IgorGanapolsky
    IgorGanapolsky over 10 years
    @hcpl You didn't mean 'Intent.hasExtra', you meant 'data.hasExtra' - assuming data is your Intent parameter in onActivityResult().
  • bugraoral
    bugraoral over 10 years
    Intent which you will receive from the gallery will provide you the url
  • abbath
    abbath over 10 years
    This code is working perfectly preKitkat, but from then there are document providers. In my answer I write about what to do in kitkat.
  • Johan
    Johan about 10 years
    I get the onActivityResult before I select an image. When I select an image, I get no onActivityResult at all. Testing on samsung s3. Really annoying.. why do I have this problem and not you?
  • Johan
    Johan about 10 years
    I get onActivityResult before picture is selected and no onActivityResult after picture is selected so it does not work for me on samsung s3.
  • nommer
    nommer about 10 years
    managedQuery() is deprecated in API 11, can either use CursorLoader which is a bit overkill for this IMHO, or just use getContentResolver().query() like in Khobaib's answer (stackoverflow.com/a/17285119/2048266)
  • Arun Badole
    Arun Badole over 9 years
    Really useful answer, should be used for selecting images from "Photos" app.
  • Arun Badole
    Arun Badole over 9 years
    I tried this on both local & server's files, worked for both.
  • Narendra Singh
    Narendra Singh about 9 years
    @hcpl whats the "action" in if (Intent.ACTION_SEND_MULTIPLE.equals(action))?
  • Narendra Singh
    Narendra Singh about 9 years
    @hcpl trying to pick multiple images .........it return null, java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=65538, result=-1, data=Intent { dat=content://media/external/images/media/1944 flg=0x1 }} to activity {com.abs_ind.www.example/com.abs_ind.www.example.MainActivit‌​y}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.Iterator java.util.ArrayList.iterator()' on a null object reference
  • hcpl
    hcpl almost 9 years
    @DroidWormNarendra action should've been a property on the data (intent) object so use data.getAction() there instead. I'll update code example.
  • Takermania
    Takermania almost 9 years
    This question has been answered step by step in this tutorial : stackoverflow.com/questions/30506301/…
  • Tom Kincaid
    Tom Kincaid over 8 years
    The multiple image selector is not working for me. It launches the picker and allows multiple selection, but in onActivityResult, data.getAction() is null, and data.hasExtra(Intent.EXTRA_STREAM) is false.
  • Tom Kincaid
    Tom Kincaid over 8 years
    This answer got the uris from multiple selection stackoverflow.com/questions/21071098/…
  • Alberto Méndez
    Alberto Méndez over 8 years
    The "getPath" method in the "Single Picture Selection" way returns null if the user choose a image from the "Recent" option in the gallery (tried in Lollipop), I solved it by directly using the Uri
  • Craig Russell
    Craig Russell about 8 years
    As a previous comment also addresses, Intent.hasExtra is a mistake in the post and should be updated to data.hasExtra. I tried to edit it to this effect but my edit was rejected; not sure why as the current code wouldn't compile and only serve to confuse people further.
  • Pankaj
    Pankaj almost 8 years
    It's working for me I am using Nexus 5 with Marshmallow. Which phone you are using.
  • Erum
    Erum almost 8 years
    i m also usng google nexus but faled to get image name or path of my gallery selected image i m getting null
  • Erum
    Erum almost 8 years
    java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/images/media from pid=31332, uid=11859 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission() getting this error
  • Pankaj
    Pankaj almost 8 years
    You have add permission which its showing READ_EXTERNAL_STORAGE
  • Erum
    Erum almost 8 years
    yes i already have added permission in manifest but i did not add any permission in java files at runtime
  • AbdulMomen عبدالمؤمن
    AbdulMomen عبدالمؤمن almost 8 years
  • Stoycho Andreev
    Stoycho Andreev over 7 years
    I face similar problem and picturePath is always null . I try you solution but does not work , plus that getDocumentId requires > API 19
  • Ankita Shah
    Ankita Shah over 7 years
    This is working if we picked image from recent images from image pick intent. Not working when user picked image from gallery.
  • Mr_Anderson
    Mr_Anderson over 7 years
    if (Intent.ACTION_SEND_MULTIPLE.equals(data.getAction())&& data.hasExtra(Intent.EXTRA_STREAM)) returns FALSE
  • Derlin
    Derlin over 6 years
    This is the easiest answer (and the only one that worked for me). So nicely done!
  • Jeremy Caney
    Jeremy Caney about 2 years
    This question has long been answered, and has a few answers that have been repeatedly validated by the community. Why do you prefer this over the existing answers?