Search code examples
androidandroid-jetpack-composeuriandroid-imageimagepicker

Open failed: EACCES (Permission denied) Exception from Image Picker


In my jetpack compose project, I have an image picker, and when I pick an image from the recents list and do a custom image compression operation, it works fine, but if the image is picked from the gallery or files app, the image compression code throws an error stating that it couldn't find the file even though the file exists in that location. What could be the issue?

Exception message

/storage/3134-6133/Pictures/Fruits/Bananas Organic.jpg: open failed: EACCES (Permission denied)

Error message

E/MediaProvider: Couldn't find file: /storage/3134-6133/Pictures/Fruits/Bananas Organic.jpg
override fun compressItemImage(context: Context, sharedViewModel: SharedViewModel) {
    viewModelScope.launch(Dispatchers.IO) {
        try {
            val compressedImageUri = context.compressImage(
                _addItemScreenState.value.editedItemImageUri?.toUri()!!,
                "item_images",
                "item_image_compressed"
            )
            setStateValue(ITEM_IMAGE_URI_STR, compressedImageUri)

            val thumbnailUri = context.createImageThumbnail(
                _addItemScreenState.value.editedItemImageUri?.toUri()!!,
                "thumbnails/item_thumbnails",
                "item_image_thumbnail"
            )
            setStateValue(ITEM_THUMBNAIL_URI_STR, thumbnailUri)

            if (sharedViewModel.isEdit.value) {
                updateShoppingListItemToDb()
            } else {
                addShoppingListItemToDb()
            }
        } catch (e: Exception) {
            setStateValue(
                IS_NAVIGATE_TO_LIST_SCREEN_STR,
                false
            )
        }
    }
}
@RequiresApi(Build.VERSION_CODES.Q)
suspend fun Context.compressImage(imageUri: Uri, destFolder: String, filePrefix: String): Uri {
    var newUri: Uri = Uri.EMPTY
    try {
        val originalFile: File = UriUtils.uri2File(imageUri)
        val timestamp = System.currentTimeMillis()
        val directory =
            File(this.getExternalFilesDir(Environment.DIRECTORY_PICTURES), destFolder)
        if (!directory.exists()) directory.mkdirs()

        val newFile = File(
            directory.absolutePath,"${filePrefix}_${timestamp}" + ".jpg"
        )

        newFile.createNewFile()

        Compressor.compress(this, originalFile) {
            default(format = Bitmap.CompressFormat.JPEG)
            destination(newFile)
        }

        newUri = FileProvider.getUriForFile(
            this,
            applicationContext.packageName + ".fileprovider",
            newFile
        )
    } catch (e: Exception) {
        Toast.makeText(this, "Unable to process your image.", Toast.LENGTH_SHORT).show()
    }

    return newUri
}

file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-files-path
        name="my_images"
        path="Android/data/<app-package>/files/Pictures"/>
    <external-files-path
        name="my_debug_images"
        path="/storage/emulated/0/Android/data/<app-package>/files/Pictures/"/>
    <external-files-path
        name="root_images"
        path="/"/>
    <external-files-path
        name="extfiles"
        path="."/>
    <external-path name="photos" path="." />

</paths>

Solution

  • In my case, I needed to ask for the READ_EXTERNAL_STORAGE permission also. My current code only asked for ACCESS_MEDIA_LOCATION permission. Everything is working now.