Search code examples
androidlocal-storageandroid-10.0android-external-storagescoped-storage

How to get URI from filename which is saved in the external Storage using Scoped Storage in android 10 and above?


Before SDK 29 this is the correct way to find the Uri but now it won't work anymore for sdk greater than 28. Let's assume I save the BITMAP using scoped-storage like:

@RequiresApi(api = Build.VERSION_CODES.Q)
@NonNull
private Uri saveBitmap(@NonNull final Context context, @NonNull final Bitmap bitmap,
                       @NonNull final Bitmap.CompressFormat format, @NonNull final String mimeType,
                       @NonNull final String displayName, @Nullable final String subFolder) throws IOException {
    String relativeLocation = Environment.DIRECTORY_PICTURES;

    if (!TextUtils.isEmpty(subFolder)) {
        relativeLocation += File.separator + subFolder;
    }

    final ContentValues contentValues = new ContentValues();
    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName);
    contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
    contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);

    final ContentResolver resolver = context.getContentResolver();

    OutputStream stream = null;
    Uri uri = null;

    try {
        final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        uri = resolver.insert(contentUri, contentValues);

        if (uri == null) {
            throw new IOException("Failed to create new MediaStore record.");
        }

        stream = resolver.openOutputStream(uri);

        if (stream == null) {
            throw new IOException("Failed to get output stream.");
        }

        if (!bitmap.compress(format, 95, stream)) {
            throw new IOException("Failed to save bitmap.");
        }

        return uri;
    } catch (IOException e) {
        if (uri != null) {
            // Don't leave an orphan entry in the MediaStore
            resolver.delete(uri, null, null);
        }

        throw e;
    } finally {
        if (stream != null) {
            stream.close();
        }
    }
}

This code works for SDK <= 28. But, How to get URI using fileName which is saved in the external storage for SDK version 29 and above?

private String getFilePathUri(String enteredFileName) {

    String file_uri_string = Environment.getExternalStorageDirectory() + "/"
            + AppConstants.APP_FOLDER + "/" + enteredFileName + ".jpg";
    AppUtils.showLog(TAG, file_uri_string + "");
    return file_uri_string;

}

Solution

  • Android 10 and above: Here the uri gives the file_id based you the given displayName.

    /**
     * Returns the Uri which can be used to delete/work with images in the photo gallery.
     * @param displayName Path to IMAGE on SD card
     * @return Uri in the format of... content://media/external/images/media/[NUMBER]
     */
    private Uri getUriFromPath(String displayName) {
        long photoId;
        Uri photoUri = MediaStore.Images.Media.getContentUri("external");
    
        String[] projection = {MediaStore.Images.ImageColumns._ID};
        // TODO This will break if we have no matching item in the MediaStore.
        Cursor cursor = getContentResolver().query(photoUri, projection, MediaStore.Images.ImageColumns.DISPLAY_NAME + " LIKE ?", new String[] { displayName }, null);
        assert cursor != null;
        cursor.moveToFirst();
    
        int columnIndex = cursor.getColumnIndex(projection[0]);
        photoId = cursor.getLong(columnIndex);
    
        cursor.close();
        return Uri.parse(photoUri.toString() + "/" + photoId);
    }