Pick image from Gallery - File not found when running newer Android versions

pick image from gallery android nougat
android get image path from gallery

I am working on a address book like Android SDK 14+ app. The users should be able to pick an image from the Gallery to add it to a contact entry.

Running the following code to pick and copy the image is no problem in API 14-20 but does not work in API 21+. The file is not found anymore:

protected void pickFoto() {
    if (filePermissionsRequired()) {
        askForFilePermissions(new PermissionRequestCompletionHandler() {
            @Override
            public void onPermissionRequestResult(boolean permissionGranted) {
                if (permissionGranted)
                    addOrEditReceipt();
            }
        });
        return;
    }

    Intent pickPhotoIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(pickPhotoIntent , PICK_FOTO_ACTION);
}

protected void onActivityResult(int requestCode, int resultCode, Intent intent) { 
    super.onActivityResult(requestCode, resultCode, intent); 

    if (resultCode == Activity.RESULT_OK) {
        switch (requestCode) {
            ...
            case PICK_FOTO_ACTION: {
                Uri imageUri = intent.getData();

                String[] filePathColumn = {MediaStore.Images.Media.DATA};
                Cursor cursor = getContentResolver().query(imageUri, filePathColumn, null, null, null);
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String filePath = cursor.getString(columnIndex);
                cursor.close();

                File imgFile = new File(filePath);
                if (imgFile.exists()) 
                    // use the file...
                else 
                    Toast.makeText(this, "Image file not found",  Toast.LENGTH_LONG).show();

                break;
        }
    }



public interface PermissionRequestCompletionHandler {
    void onPermissionRequestResult(boolean permissionGranted);
}

private PermissionRequestCompletionHandler permissionRequestCompletionHandler;
public boolean filePermissionsRequired() {
    if (Build.VERSION.SDK_INT >= 23)
        return checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
    else
        return false;
}

public boolean askForFilePermissions(PermissionRequestCompletionHandler completionHandler) {
    if (Build.VERSION.SDK_INT >= 23) {
        permissionRequestCompletionHandler = completionHandler;
        boolean hasPermission = this.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;

        if (!hasPermission) {
            this.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
            return true;
        }
    }

    permissionRequestCompletionHandler = null;
    return false;
}

The app has runtime permissions to access the Gallery. So what am I doing wrong? How to access the file on newer API versions? }

try below code to open the camera and getting result:

File file = new File(Environment.getExternalStorageDirectory() + "/DCIM/", "image" + System.currentTimeMillis() + ".png");
        Uri imageUri = Uri.fromFile(file);

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(intent, PICK_FOTO_ACTION);

for getting result :

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            switch (requestCode) {

                case PICK_FOTO_ACTION: {
                    Uri imageUri = imageUri;

                    File imgFile = new File(imageUri.getPath());
                    if (imgFile.exists())
                    // use the file...
                else
                    Toast.makeText(this, "Image file not found",  Toast.LENGTH_LONG).show();

                    break;
                }
            }
    }

for getting actual path from uri :

public String getPath(Uri uri) 
    {
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = managedQuery(uri, projection, null, null, null);
        if (cursor == null) return null;
        int column_index =             cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String s=cursor.getString(column_index);
        cursor.close();
        return s;
    }

remove unwanted uri part :

public String RemoveUnwantedString(String pathUri){
    //pathUri = "content://com.google.android.apps.photos.contentprovider/-1/2/content://media/external/video/media/5213/ORIGINAL/NONE/2106970034"
    String[] d1 = pathUri.split("content://");
    for (String item1:d1) {
        if (item1.contains("media/")) {
            String[] d2 = item1.split("/ORIGINAL/");
            for (String item2:d2) {
                if (item2.contains("media/")) {
                    pathUri = "content://" + item2;
                    break;
                }
            }
            break;
        }
    }
    //pathUri = "content://media/external/video/media/5213"
    return pathUri;
}

Pick image from Gallery, For versions 21 and higher you can do this , you need to add a condition to check the SDK version for this. Exectute this code in the API 21+ condition block. Sometimes, you can't get a file from the picture you choose. It's because the choosen one came from Google+, Drive, Dropbox or any other provider. The best solution is to ask the system to pick a content via Intent.ACTION_GET_CONTENT and get the result with a content provider.

For versions 21 and higher you can do this , you need to add a condition to check the SDK version for this. Exectute this code in the API 21+ condition block.

    String wholeID = DocumentsContract.getDocumentId(imageUri );
    String id = wholeID.split(":")[1];
    String sel = MediaStore.Images.Media._ID + "=?";

    cursor =  
    getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
                                  projection, sel, new String[]{ id }, null);
    try
     {
      int column_index = cursor
           .getColumnIndex(MediaStore.Images.Media.DATA);
      cursor.moveToFirst();
      path = cursor.getString(column_index).toString();
      cursor.close();
      }
    catch(NullPointerException e) {

      }

[Android Example] Pick Image from Gallery or Camera, Simple Android tutorial to pick image from Gallery or capture image using Not every app needs to design a camera/gallery to allow user to pick image. For devices running on and above Android Marshmallow version, we need Since Nougot version Android has restricted apps to share file URIs with  This application supports image selection from Gallery application and it may not work as expected if you pick Image from other image applications (like Google Photos application present in higher version of Android). I will write separate post later on how to pick Images from sources other than Gallery app.

Call the Gallery with belo code

public static final int SELECT_IMAGE_FROM_GALLERY_CODE = 701;
public static void callGallery(Activity activity) {
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        activity.startActivityForResult(Intent.createChooser(intent, "Complete action using"),
                SELECT_IMAGE_FROM_GALLERY_CODE);
}

In OnActivityResult, read URI and read path from uri.

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == CommonUtils.SELECT_IMAGE_FROM_GALLERY_CODE) {

            if (data != null) {
                Uri selectedImageUri = data.getData();
                // get path from Uri
                String imagepath = getPath(this, selectedImageUri);

                if (null != imagepath && (!imagepath.isEmpty())) {
                    // if the image path is not null and not empty, copy image to sdcard
                    try {
                        copyDirectoryOrFile(new File(imagepath), new File(myTargetImageFilePath));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    // load the image into imageView with the help og glide.
                    loadImageWithGlide(myImageViewContactImage,
                            myTargetImageFilePath, myDefaultImagePath, myErrorImagePath, false);

                } else {
                    Toast.makeText(this,  "Error: Photo selection failed.", Toast.LENGTH_LONG).show();
                }
            }
        }
}

public void loadImageWithGlide(ImageView theImageViewToLoadImage,
                                   String theLoadImagePath, int theDefaultImagePath, int theErrorImagePath,
                                   boolean theIsSkipMemoryCache) {

        if (theIsSkipMemoryCache) {
            Glide.with(ProfileActivity.this) //passing context
                    .load(theLoadImagePath) //passing your url to load image.
                    .placeholder(theDefaultImagePath) //this would be your default image (like default profile or logo etc). it would be loaded at initial time and it will replace with your loaded image once glide successfully load image using url.
                    .error(theErrorImagePath)//in case of any glide exception or not able to download then this image will be appear . if you won't mention this error() then nothing to worry placeHolder image would be remain as it is.
                    .diskCacheStrategy(DiskCacheStrategy.ALL) //using to load into cache then second time it will load fast.
                    //.animate(R.anim.fade_in) // when image (url) will be loaded by glide then this face in animation help to replace url image in the place of placeHolder (default) image.
                    .centerCrop()
                    .into(theImageViewToLoadImage); //pass imageView reference to appear the image.
        } else {
            Glide.with(ProfileActivity.this)
                    .load(theLoadImagePath)
                    .diskCacheStrategy(DiskCacheStrategy.NONE)
                    .skipMemoryCache(true)
                    .centerCrop()
                    .into(theImageViewToLoadImage);
        }
    }

    public static String getPath(Context theCtx, Uri uri) {
        try {
            Cursor cursor = (theCtx).getContentResolver().query(uri, null, null, null, null);
            cursor.moveToFirst();
            String document_id = cursor.getString(0);
            document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
            cursor.close();

            cursor = (theCtx).getContentResolver().query(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
            cursor.moveToFirst();
            String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            cursor.close();

            return path;
        } catch (Exception e) {
            return null;
        }
    }

    public static void copyDirectoryOrFile(File sourceLocation, File targetLocation)
            throws IOException {

        if (sourceLocation.isDirectory()) {
            if (!targetLocation.exists() && !targetLocation.mkdirs()) {
                throw new IOException("Cannot create directory " + targetLocation.getAbsolutePath());
            }

            String[] children = sourceLocation.list();
            for (int i = 0; i < children.length; i++) {
                copyDirectoryOrFile(new File(sourceLocation, children[i]),
                        new File(targetLocation, children[i]));
            }
        } else {
            File directory = targetLocation.getParentFile();
            if (directory != null && !directory.exists() && !directory.mkdirs()) {
                throw new IOException("Cannot create directory " + directory.getAbsolutePath());

            }

            InputStream in = new FileInputStream(sourceLocation);
            OutputStream out = new FileOutputStream(targetLocation);

            // Copy the bits from instream to outstream
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            in.close();
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

To load image with glide, add following dependency in app gradle file

compile 'com.github.bumptech.glide:glide:3.7.0'

ImagePicker.pickImage() never returns on android · Issue #19103 , What happens is I pick a photo from a gallery (or take a photo with camera an Doctor summary (to see all details, run flutter doctor -v): [√] Flutter (Channel Studio at C:\Program Files\Android\Android Studio • Flutter plugin version android-arm64 • Android 8.0.0 (API 26) (emulator) • No issues found! Apparantely, this code works if you try to pick the photos from camera. If the user has a picasa account and if you try to pick the photo from picasa albums (which also shows up in gallery), it throws a null pointer exception in im.setImageBitmap(image); because your filepath is null.the path of the picasa album is different from the path of camera (local) pictures.

Accessing the Camera and Stored Media, The easy way - launch the camera with an intent, designating a file path, and to take a picture and return control to the calling application Intent intent = new Create the storage directory if it does not exist if (!mediaStorageDir.exists() && ! resolveActivity(getPackageManager()) != null) { // Bring up gallery to select a  Hello, and welcome to pick image from gallery or camera in android studio example. Pick image from gallery or camera in android tutorial guides you how to select/get the image from a gallery in android programmatically. We will choose/take a photo from gallery or camera in the Android Studio by opening via Intent.

Access media files from shared storage, Images, including photographs and screenshots, which are stored in the DCIM/ and Downloads collection, without requesting any storage-related permissions. To find media that satisfies a particular set of conditions, such as a duration of 5 preview versions—or thumbnails—of the files instead of the files themselves. Pick Image From Gallery Or Google Photos Failing. I don't see the Cursor object being created to pick image from Gallery, try this code File fileDirectory

Take photos, You want to take photos with minimal fuss, not reinvent the camera. only on the lower versions of Android by adding the maxSdkVersion attribute: in a method that returns a unique file name for a new photo using a date-time stamp: If you find your application running out of memory after displaying just a few images,  Anyway found other solution which is to force opening image gallery instead of KITKAT documents view with : // KITKAT i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(i, CHOOSE_IMAGE_REQUEST); and then load the image:

Comments
  • show the codes where the app asks the users to grant permission.
  • add runtime permission on above marshmallow devices
  • have you done run time permission in your app for external storage?
  • Yes, runtime permissions are granted (my code check this)
  • Thanks, but this has nothing to do with the question since I would like to pick an existing picture from the gallery and not take a new picture...
  • Sorry but could you describe in more detail how to apply this my question? Actually I would need just the RemoveUnwantedString method, right? This should be applied to imageUri? However the result also leeds to an non existing file...
  • first check in debug or in log that your uri is getting correct or not. if getting not in correct format, use RemoveUnwantedString() method else use getPath() method to get correct path of file from uri. @AndreiHerford
  • This throws an java.lang.IllegalArgumentException: Invalid URI: content://com.google.android.apps.photos.contentprovider... in the very first line when calling DocumentsContract.getDocumentId(imageUri). BTW what is projection in getContentResolver().query(..., projection, ...)?