0

I'm using image picker to select a image and then uploading this image to the server .

My code is working perfectly in all android devices except for Mi phones.

For all device Uri returned is of type : content://media/external/images/media/523

For Mi devices Uri returned is of type:file:///storage/emulated/0/DCIM/Camera/IMG_20160912_160415.jpg

The Cursor cursor = context.getContentResolver().query() returns null if the uri is not in format content://*

 private void pickImage() {

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

        startActivityForResult(photoPickerIntent, 0);
    }

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



        if (resultCode == RESULT_OK) {
            Uri selectedImageUri = data.getData();
            if (selectedImageUri != null) {
                selectedImagePath = Utils.getImagePath(selectedImageUri, DepositBankWireActivity.this);
                Log.i("uplaod", "selectedImagePath" + selectedImagePath);
}
}

 public static String getImagePath(Uri uri, Context context) {
        Log.i("getImagePath",""+uri+" mime "+getMimeType(uri,context));

            String[] projection = {MediaStore.MediaColumns.DATA,
                    MediaStore.Images.ImageColumns.ORIENTATION};
            Cursor cursor = context.getContentResolver().query(uri, projection, null, null,
                    null);
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);

    }

Is there a standard way to implement image picker which returns the correct image path from uri eg /storage/emulated/0/Pictures/Screenshots/test.png for upload.

Rachita Nanda
  • 4,509
  • 9
  • 42
  • 66

1 Answers1

1

There is no requirement for the DATA column of MediaStore to give you a filesystem path that you can use. For example, the image might be on removable storage on Android 4.4+, which the MediaStore can access, but you cannot. MediaStore can also have in its index images that are not local to the device, but are from services like Google Photos (so I've been told).

So, your first step is to get rid of getImagePath(), as it will be unreliable.

The simplest and most performant solution is to find a way to "compress the images and [do] a multipart image upload on the server" without filesystem access. For example, you have access to an InputStream via openInputStream() on ContentResolver, and that will work for both types of Uri shown in your question. Find some way to do your work using that InputStream.

If you determine that this is not possible, you will need to get that InputStream anyway and make a local copy of the content (e.g., in getCacheDir()). Then, use your local copy, deleting it when you are done.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • in addition to what CommonsWare said you could use `File#createTempFile` to create a tmp file – pskink Sep 14 '16 at 12:38
  • Is there a reliable 3rd alternative that preserves images exactly? I _was_ in fact doing what's suggested in this answer, but decided to move away from it for the simple reason that it doesn't ensure data integrity (of photos in my case). Since I only get an `InputStream` with no information as to the original encoding of the photo, the image I create might have a lower quality than the original, depending on the JPEG compression settings I use. – Vicky Chijwani Feb 05 '17 at 02:37
  • Also, duplicating the original data is decidedly _not_ performant, especially if there are additional resource-intensive steps involved, like JPEG compression in the case of photos. – Vicky Chijwani Feb 05 '17 at 02:40
  • I've ended up using a hybrid approach: I try to convert the URI to a filesystem path first, and if that fails, fall back to reading the `InputStream`, convert it to a JPEG image and upload that. This should be robust while preserving the original data as far as possible. To convert URI => path I'm using this utility class that seems to handle a lot of edge-cases: https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java – Vicky Chijwani Feb 05 '17 at 03:11
  • @VickyChijwani: "Since I only get an InputStream with no information as to the original encoding of the photo" -- you get the raw bytes of whatever the photo is (e.g., JPEG). The JPEG will contain the details of the encoding of the JPEG. "duplicating the original data is decidedly not performant" -- then don't duplicate the data. "I'm using this utility class that seems to handle a lot of edge-cases" -- it handles very few cases, in terms of the overall Android ecosystem, and may cause your app to crash (e.g., the inferred path is on removable storage). – CommonsWare Feb 05 '17 at 12:51
  • @CommonsWare thanks for the info, could you please point me to a resource (or a library) which explains how to handle all the edge-cases you refer to? And you're right about the image encoding, I obviously should've that through more carefully. – Vicky Chijwani Feb 06 '17 at 12:46
  • @VickyChijwani: "could you please point me to a resource (or a library) which explains how to handle all the edge-cases you refer to?" -- there is none, other than to use the `Uri` properly, as I outlined in the answer to this question. – CommonsWare Feb 06 '17 at 12:52