Pick Image From Gallery Or Google Photos Failing

13,621

Solution 1

Try getPathFromInputStreamUri(), this will fix the content uri problem from google photo app

Kotlin (UPDATED)

fun getPathFromInputStreamUri(context: Context, uri: Uri): String? {
    var filePath: String? = null
    uri.authority?.let {
        try {
            context.contentResolver.openInputStream(uri).use {
                val photoFile: File? = createTemporalFileFrom(it)
                filePath = photoFile?.path
            }
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
    return filePath
}

@Throws(IOException::class)
private fun createTemporalFileFrom(inputStream: InputStream?): File? {
    var targetFile: File? = null
    return if (inputStream == null) targetFile
    else {
        var read: Int
        val buffer = ByteArray(8 * 1024)
        targetFile = createTemporalFile()
        FileOutputStream(targetFile).use { out ->
            while (inputStream.read(buffer).also { read = it } != -1) {
                out.write(buffer, 0, read)
            }
            out.flush()
        }
        targetFile
    }
}

private fun createTemporalFile(): File = File(getDefaultDirectory(), "tempPicture.jpg")

Java

public static String getPathFromInputStreamUri(Context context, Uri uri) {
    InputStream inputStream = null;
    String filePath = null;

    if (uri.getAuthority() != null) {
        try {
            inputStream = context.getContentResolver().openInputStream(uri);
            File photoFile = createTemporalFileFrom(inputStream);

            filePath = photoFile.getPath();

        } catch (FileNotFoundException e) {
            Logger.printStackTrace(e);
        } catch (IOException e) {
            Logger.printStackTrace(e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    return filePath;
}

private static File createTemporalFileFrom(InputStream inputStream) throws IOException {
    File targetFile = null;

    if (inputStream != null) {
        int read;
        byte[] buffer = new byte[8 * 1024];

        targetFile = createTemporalFile();
        OutputStream outputStream = new FileOutputStream(targetFile);

        while ((read = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, read);
        }
        outputStream.flush();

        try {
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return targetFile;
}

private static File createTemporalFile() {
    return new File(Utils.getDefaultDirectory(), "tempPicture.jpg");
}

Solution 2

The Uri might be like this content://com.google.android.apps.photos.content/0/https%3A%2F%2Flh3.googleusercontent.com%2FL-3Jm0TaSqnuKkitli5mK0-d

& its not of your local device. Local device's Uri will be like this

content://media/external/images/media/49518

Because of this difference your uriToPath(Uri uri) is returning null.

So check the Uri first & accordingly fetch image from local device or server.

You can use DocumentsProvider API so you won't have to worry about the local & server's files.

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;
}

But if you have some local photos in Photos app then on selecting those you will get the local Uri, which will give you the correct file path.

You can also download the photos (which are on Google server) in Photos app itself & later use it.

Source:

Solution 3

I don't see the Cursor object being created to pick image from Gallery, try this code

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

    //FROM CAMERA
    if (requestCode == 1) {
        if (resultCode == getActivity().RESULT_OK) {
            Bitmap bp = (Bitmap) data.getExtras().get("data");

            File fileDirectory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Documents/Images/");


    }

    //FROM GALLERY
    else
    if (resultCode == getActivity().RESULT_OK && RESULT_LOAD_IMG == 2) {
        {
            File fileDirectory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Documents/TWINE/");
            Uri selectedImage = data.getData();
            String[] filePathColumn = {MediaStore.Images.Media.DATA};

            // Get the cursor
            Cursor cursor = AppController.getInstance().getContentResolver().query(selectedImage,
                    filePathColumn, null, null, null);
            // Move to first row
            cursor.moveToFirst();

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

            File fileGallery = new File(imgDecodableString);
            Bitmap bitmap = BitmapFactory.decodeFile(fileGallery.getAbsolutePath());


            cursor.close();

            // Set the Image in ImageView after decoding the String
            Log.d("Bitmap", "Bit");

            imageName = UUID.randomUUID().toString() + ".JPG";

            imagePath = fileDirectory + "/" + imageName;

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);
            byte[] b = baos.toByteArray();

            File file = new File(fileDirectory, imageName);

            try {
                FileOutputStream out = new FileOutputStream(file);
                out.write(b);
                out.flush();
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }


        }
    }
}

Dialog Box to let user choose options:

private void selectImage() {
    final CharSequence[] items = { "Take Photo", "Choose from Gallery", "Cancel" };
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setTitle("Add Photo!");
    builder.setItems(items, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int item) {
            if (items[item].equals("Take Photo")) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(intent, 1);
            } else if (items[item].equals("Choose from Gallery")) {
                Intent galleryIntent = new Intent(Intent.ACTION_PICK,
                        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                // Start the Intent
                startActivityForResult(galleryIntent, RESULT_LOAD_IMG);
            } else if (items[item].equals("Cancel")) {
                dialog.dismiss();
            }
        }
    });
    builder.show();
}
Share:
13,621

Related videos on Youtube

Petro
Author by

Petro

Favorite lang: Java

Updated on June 05, 2022

Comments

  • Petro
    Petro about 2 years

    EDIT: I wanted to update what the problem really is. On a Samsung phone you have "Gallery", inside "Gallery" you can also see your google photos backups. This is the photo selection I'm trying to get at. Now on other apps (Close5) they simply display a message stating "That photo is not supported". But why? Why can't we get this url (https:/lh3.googleusercontent) to work?

    E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /https:/lh3.googleusercontent.com/-Llgk8Mqk-rI/U8LK0SMnpWI/AAAAAAAAFk4/0cktb59DnL8GgblJ-IJIUBDuP9MQXCBPACHM/I/IMG_20140711_085012.jpg: open failed: ENOENT (No such file or directory)

    You can all clearly see this is a real photo with a real url:

    https:/lh3.googleusercontent.com/-Llgk8Mqk-rI/U8LK0SMnpWI/AAAAAAAAFk4/0cktb59DnL8GgblJ-IJIUBDuP9MQXCBPACHM/I/IMG_20140711_085012.jpg
    

    Everything works fine until I go to select from photos or a google photos image instead of from the gallery, I tried handling the exception (Sorry, that image isn't supported. Try another gallery!) but that seems incomplete. I tried looking at other solutions on here but none of them worked for google photos. Thanks!

    Error is a null pointer with:

    app E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /https:/lh3.googleusercontent

     @Override
        public void onActivityResult(int requestCode, int resultCode,
                                        Intent data) {
            if (resultCode != Activity.RESULT_CANCELED) {
                    if (requestCode == 1) {
                        try{
                        String selectedImagePath = getAbsolutePath(data.getData());                          ((PostAdParentTabHost)getActivity()).getMap_of_picture_paths().put(1, selectedImagePath);                      
                        post_ad_camera_img_1.setImageBitmap(decodeSampledBitmapFromFileToCustomSize(selectedImagePath, 150, 150));
                        animation_master.fade(post_ad_camera_img_1);
                        }catch(Exception e){
                            e.printStackTrace();
                            ((PostAdParentTabHost)getActivity()).getMap_of_picture_paths().remove(requestCode);
                            Toast.makeText(getActivity(), "Sorry, that image isn't supported. Try another gallery! ", Toast.LENGTH_SHORT).show();
                        }
    
    //------------------------------------------------------Methods:
    public String getAbsolutePath(Uri uri) {
        Uri final_uri = uri;
            if (uri.getLastPathSegment().contains("googleusercontent.com")){
                final_uri = getImageUrlWithAuthority(getActivity(), uri);
                String[] projection = { MediaStore.MediaColumns.DATA };
                Cursor cursor = getActivity().getContentResolver().query(final_uri, projection, null, null, null);
                if (cursor != null) {
                    int column_index = cursor
                            .getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                    cursor.moveToFirst();
                    return cursor.getString(column_index);
                }else{
    
                    return null;
                }
            }else{
            String[] projection = { MediaStore.MediaColumns.DATA };
            Cursor cursor = getActivity().getContentResolver().query(final_uri, projection, null, null, null);
            if (cursor != null) {
                int column_index = cursor
                        .getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                cursor.moveToFirst();
                return cursor.getString(column_index);
            }else{
    
                return null;
            }
    
        }
    
     public static Uri 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);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }finally {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
    
    public 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);
    }
    
          public Uri setImageUri() {
            // Store image in dcim
            File file = new File(Environment.getExternalStorageDirectory()
                    + "/DCIM/", "image" + new Date().getTime() + ".png");
            Uri imgUri = Uri.fromFile(file);
            this.image_as_uri_for_parcel = imgUri;
            this.imgPath = file.getAbsolutePath();
            return imgUri;
    
    }
    
  • Petro
    Petro over 8 years
    When I take a photo it works, but nothing populates in my imageview from gallery, I'll have to play around more. I'll give you a bump in rep for now, I'll try to figure out the rest in the morning + mark this correct. Thanks!
  • Petro
    Petro almost 4 years
    Marking this as the correct answer, since it solves the problem and is up to date