androiduriandroid-storage

How to get permanent access to file URI


for the last 2 days I've been trying to implement a profile picture feature into an application using Uri and it works... for android versions < 11, and this is probably the reason, so I wanted to ask, how should I handle this problem ? Should I copy the files, store them application storage and then get the Uri? The code I'm currently using is based on this:

    private var currentPhotoUri: Uri = Uri.EMPTY
    private var isChanged = false

    // intent launcher used for the profile picture image, on result it updates the picture
    private val intentLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            if (it.resultCode == Activity.RESULT_OK) {
                val photoResult: Uri? = it.data?.data
                if(photoResult != null) {
                    // user picked from gallery
                    currentPhotoUri = photoResult
                    changeProfilePicture(photoResult) // just a function that saves the Uri with room
                } else {
                    // user made a photo
                    changeProfilePicture(currentPhotoUri)
                }
            }
        }
    private fun openIntentChooserForImageSources() {
        // creating gallery intent
        val galleryIntent = Intent(Intent.ACTION_OPEN_DOCUMENT, MediaStore.Images.Media.INTERNAL_CONTENT_URI)
        galleryIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

        // creating camera intent
        val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        cameraIntent.also { takePictureIntent ->
            takePictureIntent.resolveActivity(requireActivity().packageManager)?.also {
                val photoFile: File? = try {
                    createImageFile()
                } catch (e: IOException){
                    null
                }
                photoFile?.also {
                    val photoFileUri: Uri = FileProvider.getUriForFile(
                        requireContext(),
                        requireActivity().packageName,
                        it
                    )
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoFileUri)
                }
            }
        }

        val intentChooser = Intent.createChooser(galleryIntent, "Select an app")
        intentChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(cameraIntent))
        intentLauncher.launch(intentChooser)
    }
    @Throws(IOException::class)
    private fun createImageFile(): File {
        // Create an image file name
        val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
        val storageDir = requireActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        return File.createTempFile(
            "JPEG_${timeStamp}_", /* prefix */
            ".jpg", /* suffix */
            storageDir /* directory */
        ).apply {
            currentPhotoUri = this.toUri()
        }
    }

Solution

  • the error I get: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord (...) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs

    For the case where you use ACTION_OPEN_DOCUMENT, call takePersistableUriPermission() on a ContentResolver to get durable access to the content.