50

My app has ability to select photo from library. Exactly I want file path from this selection.

This is the code to create intent for selecting photo:

    Intent photoPickerIntent = new Intent(Intent.ACTION_PICK,
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    photoPickerIntent.setType("image/*");
    startActivityForResult(photoPickerIntent, INTENT_REQUEST_CODE_SELECT_PHOTO);

This is the code that gets file path from URI:

    Cursor cursor = null;
    String path = null;
    try {
        String[] projection = { MediaStore.Images.Media.DATA };
        cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
        int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
        cursor.moveToFirst();
        path = cursor.getString(columnIndex);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return path;

Before yesterday's update of Google Photos app everything worked perfectly fine. Now path is null after parsing URI.

URI is similar to this: content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F75209/ACTUAL

I also tried to create intent with Intent.ACTION_GET_CONTENT action - no luck.

Akhil
  • 6,667
  • 4
  • 31
  • 61
Den Drobiazko
  • 1,077
  • 1
  • 13
  • 33

3 Answers3

48

Below code is working for me to get content URI on latest Google Photos as well. What i have tried is writing to temp file and return temp image URI, if it has authority in content URI.

You can try same:

private static String getImageUrlWithAuthority(Context context, Uri uri)
{
    InputStream is = null;

    if (uri.getAuthority() != null)
    {
        try
        {
            is = context.getContentResolver().openInputStream(uri);
            Bitmap bmp = BitmapFactory.decodeStream(is);
            return writeToTempImageAndGetPathUri(context, bmp).toString();
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (is != null)
                {
                    is.close();
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    return null;
}

private static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage)
{
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
    return Uri.parse(path);
}
Bugs Happen
  • 2,169
  • 4
  • 33
  • 59
Akhil
  • 6,667
  • 4
  • 31
  • 61
  • 2
    I've accepted this answer, although for our flow this is a bit of a workaround. But it allows to get app back to fully working state, so this counts. One note: I didn't do a Bitmap decoding from a InputStream - I've copied it to some `File tempFile = new File("path_to_my_temp_directory");` and then used last one for all the stuff. – Den Drobiazko Jun 04 '15 at 11:06
  • @Akhil Thanks for this! – Petro Apr 05 '16 at 02:46
  • `is = context.getContentResolver().openInputStream(uri);` is returning null. I cannot seem to find any solution for picking images from google photos app. If anyone has a working solution, please share. – ArJ Apr 08 '16 at 10:19
  • I made an answer in other question similar to this bt ussing Input and Outpu streams instead of bitmaps : http://stackoverflow.com/questions/43500164/getting-path-from-uri-from-google-photos-app – adalpari Apr 26 '17 at 14:39
  • But how to download the video file from Google photos? – Lovekush Vishwakarma Oct 26 '18 at 13:19
6

This is most certainly a workaround, but you could extract the real content URI which has apparently become embedded for some reason: content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F75209

I was able to create a new URI with authority=media and path=external/images/media/xxx, and content resolver returned a real URL.

Example code:

String unusablePath = contentUri.getPath();
int startIndex = unusablePath.indexOf("external/");
int endIndex = unusablePath.indexOf("/ACTUAL");
String embeddedPath = unusablePath.substring(startIndex, endIndex);

Uri.Builder builder = contentUri.buildUpon();
builder.path(embeddedPath);
builder.authority("media");
Uri newUri = builder.build();
  • Could you please share the source for this solution? stuck at this issue for a couple of days now! – Vishy Jun 16 '15 at 04:17
  • @JonRogstad your example works like a charm! But this is a work around for now. I think there should be a native way of handling Custom/App-Specific URIs – sud007 Jul 22 '15 at 15:34
  • this crashes on Samsung Galaxy S5, Android 5.0 – Maragues Sep 11 '15 at 08:45
  • Just a WARNING: This won't work on all devices and with all photos.. i.e. my URI looks like this... `content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F31769/ORIGINAL/NONE/##########`, with `#` indicating a digit (0-9) – Joshua King Dec 03 '18 at 16:14
1

I know this question is bit old, still I did the following to get the image from gallery and use it. Below is the extension function for the same.

fun Uri.toBitmap(context: Context?): Bitmap {
    return MediaStore.Images.Media.getBitmap(context?.contentResolver, this)
}

It takes context as parameter to get contentResolver and Uri received from onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?).

To use, just do the following:

intent?.data.toBitmap(context)

where intent?.data is the Uri received from onActivityResult().

arungiri_10
  • 988
  • 1
  • 11
  • 23