22

As I am supporting my app to Kitkat version, now in this the way of retrieve file from gallery was different.

I have preferred this Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENT for retrieving file from gallery and successfully work but I required Absolute path of that file, I am getting

content://com.android.providers.media.documents/document/image:2505

For 19 below version we used uri different by using that I am getting path this way

Cursor cursor = this.getContentResolver().query(originalUri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String fpath = cursor.getString(column_index);

but in 19 version it will give me null value how to get absolute path of image file which was selected by user.

Thanks

Community
  • 1
  • 1
Pratik
  • 30,114
  • 17
  • 82
  • 154

4 Answers4

28

Here is one way to access the Absolute path after selecting file.

After getting data in new URI format for KK(KitKat) like this way

content://com.android.providers.media.documents/document/image:2505

Just extract ID of your document

if(requestCode == GALLERY_KITKAT_INTENT_CALLED && resultCode == RESULT_OK){

    Uri originalUri = data.getData();

    final int takeFlags = data.getFlags()
                        & (Intent.FLAG_GRANT_READ_URI_PERMISSION
                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    // Check for the freshest data.
    getContentResolver().takePersistableUriPermission(originalUri, takeFlags);

    /* now extract ID from Uri path using getLastPathSegment() and then split with ":"
    then call get Uri to for Internal storage or External storage for media I have used getUri()
    */

    String id = originalUri.getLastPathSegment().split(":")[1]; 
    final String[] imageColumns = {MediaStore.Images.Media.DATA };
    final String imageOrderBy = null;

    Uri uri = getUri();
    String selectedImagePath = "path";

    Cursor imageCursor = managedQuery(uri, imageColumns,
          MediaStore.Images.Media._ID + "="+id, null, imageOrderBy);

    if (imageCursor.moveToFirst()) {
        selectedImagePath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
    }
    Log.e("path",selectedImagePath ); // use selectedImagePath 
}else if() {
      // for older version use existing code here
}

// By using this method get the Uri of Internal/External Storage for Media
private Uri getUri() {
    String state = Environment.getExternalStorageState();
    if(!state.equalsIgnoreCase(Environment.MEDIA_MOUNTED))
        return MediaStore.Images.Media.INTERNAL_CONTENT_URI;

    return MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
Pratik Butani
  • 51,868
  • 51
  • 228
  • 375
Pratik
  • 30,114
  • 17
  • 82
  • 154
  • i tried to execute this , but i recieve 01-09 12:09:49.333: E/AndroidRuntime(21760): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content: flg=0x1 }} to activity {com.example.loadimage/com.example.loadimage.MainActivity}: java.lang.SecurityException: No permission grant found for UID 10259 and Uri content: – Mr.G Jan 09 '14 at 06:41
  • seems that exception occurs in this line takePersistableUriPermission Do i have to add any sort of permission in manifest – Mr.G Jan 09 '14 at 06:46
  • 1
    its throw `Caused by: java.lang.SecurityException: Requested flags 0x1, but only 0x0 are allowed` – RobinHood Mar 03 '14 at 10:38
  • the line "getContentResolver().takePersistableUriPermission(originalUri, takeFlags);" throws a security exception in KitKat 4.4.2. If you comment it out or catch the exception it still seems to work fine. – esilver Mar 26 '14 at 17:36
  • i still get null :( – zihadrizkyef Oct 26 '16 at 01:29
  • You should use `ContentUris.parseId(originalUri)` for get the id instead of split with **:** – Hinte Aug 14 '18 at 08:05
4

Pratik's solution helped me alot. Following is the version which works for me in Kitkat 4.4.2. Three things which i changed are
1) Using content resolver to get the path
2) originalUri.getLastPathSegment().split(":")[1] gives me index out of bound so i'm using index 0 instead.Its been working so far
3) Removed takeflags and check for freshest data as we are filtering the cursor with id.

try {
        Uri originalUri = data.getData();
        String pathsegment[] = originalUri.getLastPathSegment().split(":");
        String id = pathsegment[0];
        final String[] imageColumns = { MediaStore.Images.Media.DATA };
        final String imageOrderBy = null;

        Uri uri = getUri();
        Cursor imageCursor = activity.getContentResolver().query(uri, imageColumns,
                                MediaStore.Images.Media._ID + "=" + id, null, null);

        if (imageCursor.moveToFirst()) {
            value = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
        }

    } catch (Exception e) {
        Toast.makeText(activity, "Failed to get image", Toast.LENGTH_LONG).show();
    }
Dhir Pratap
  • 1,178
  • 11
  • 14
2

Perfectly working solution:

package utils;

/**
 * Created by layer on 4/21/2015.
 */
import android.annotation.TargetApi;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

public class ImageFilePath {

    /**
     * Method for return file path of Gallery image
     *
     * @param context
     * @param uri
     * @return path of the selected image file from gallery
     */
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static String getPath(final Context context, final Uri uri) {

        // check here to KITKAT or new version
        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {

            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/"
                            + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(id));

                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[] { split[1] };

                return getDataColumn(context, contentUri, selection,
                        selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {

            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();

            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return null;
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context
     *            The context.
     * @param uri
     *            The Uri to query.
     * @param selection
     *            (Optional) Filter used in the query.
     * @param selectionArgs
     *            (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    public static String getDataColumn(Context context, Uri uri,
                                       String selection, String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = { column };

        try {
            cursor = context.getContentResolver().query(uri, projection,
                    selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri
                .getAuthority());
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri
                .getAuthority());
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri
                .getAuthority());
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is Google Photos.
     */
    public static boolean isGooglePhotosUri(Uri uri) {
        return "com.google.android.apps.photos.content".equals(uri
                .getAuthority());
    }
}

https://github.com/layerlre/Android-Utility-Class/blob/master/utils/ImageFilePath.java

Hope works for you.

Erich García
  • 1,348
  • 18
  • 27
1
Bitmap bitmap = MediaStore.Images.Media
.getBitmap(getActivity().getContentResolver(), uri);

I hope that this will help you.

isuekey
  • 59
  • 3