Home > Software engineering >  Error when writing bitmap to directory even with directory access
Error when writing bitmap to directory even with directory access

Time:05-04

What I want to do: After the user chooses a directory/folder (and thus allows the app access), I want to write a bitmap to that directory. However, I get this error when writing that bitmap:

Caused by: java.io.FileNotFoundException: /storage/emulated/0/ChosenFolderByUser/output.jpg: open failed: EPERM (Operation not permitted)

Why does this happen since the user has granted access to files in the chosen directory? Here's my code:

private val dirPickerHandler = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) {
    if (it.data != null) {

        val uri = it.data?.data!!

        contentResolver.takePersistableUriPermission(
            uri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION or
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        )

        grantUriPermission(
            packageName,
            uri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION or
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
                    Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
        )

        val path = URLDecoder.decode(uri.toString(), "UTF-8")
        val dPath = cleanPath(path)

        showMessage("Storage location successfully updated to $dPath")

        val mIcon = BitmapFactory.decodeResource(getResources(), R.drawable.image_to_save)
        // Write bitmap to directory chosen by user - Error here:
        File(Environment.getExternalStorageDirectory().toString()   "/"   dPath, "output.jpg").writeBitmap(mIcon, Bitmap.CompressFormat.JPEG, 85)

    } else {
        showMessage(
            getString(R.string.no_directory_selected)
        )
    }
}

companion object {
    fun cleanPath(path: String): String {

        if (path.isEmpty()) {
            return "DCIM/Camera"
        }

        val s = URLDecoder.decode(path, "UTF-8")
        return s.substring(s.lastIndexOf(":")   1)
    }
}

private fun File.writeBitmap(bitmap: Bitmap, format: Bitmap.CompressFormat, quality: Int) {
    outputStream().use { out ->
        bitmap.compress(format, quality, out)
        out.flush()
    }
}

CodePudding user response:

Remove the call for grantUriPermission() as it does not make sense.

Dont try to get a path for an uri.

Dont use the File class for an Uri.

You are not showing where the used output stream comes from.

CodePudding user response:

You cannot use Environment.getExternalStorageDirectory() for target SDK 31. You should use scope storage. Please read more about it here: https://developer.android.com/about/versions/11/privacy/storage

If you want to use the legacy way, you should have the target SDK 30 (max) and in case it is 30, then you should enable requestLegacyExternalStorage.

  • Related