dfjick
dfjick

Reputation: 1

Error While Upload Image From Galley Using Drjacky Image Picker And Retrofit 2

hi guys I got an error like the one below when trying to upload an image from the galley:

java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{efed650 15275:app.fadlyproject.com/u0a158} (pid=15275, uid=10158) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs

the error comes from this line of code:

val parcelFileDescriptor =
        contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?: return

I'm using 3rd party libraries namely DrJacky and Retrofit 2. I've added some necessary things to the manifest as below:

Dependencies :

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.github.Drjacky:ImagePicker:2.3.19'

Manifest :

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    image_view = findViewById(R.id.image_view)
    button_upload = findViewById(R.id.button_upload)

    image_view!!.setOnClickListener {
        openImageChooser()
    }

    button_upload!!.setOnClickListener {
        uploadImage()
    }

}                                                                              
  private val profileLauncher =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        if (it.resultCode == Activity.RESULT_OK) {
            val uri = it.data?.data!!
            selectedImageUri = uri
            image_view!!.setImageURI(selectedImageUri)
        } else parseError(it)
    }

private fun openImageChooser() {
    ImagePicker.with(this)
        .provider(ImageProvider.BOTH)
        .setDismissListener {
            Log.d("ImagePicker", "onDismiss");
        }
        .createIntentFromDialog { profileLauncher.launch(it) }
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_OK) {
        when (requestCode) {
            REQUEST_CODE_PICK_IMAGE -> {
                selectedImageUri = data?.data
                image_view!!.setImageURI(selectedImageUri)
            }
        }
    }
}

private fun uploadImage() {
    if (selectedImageUri == null) {
        layout_root!!.snackbar("Select an Image First")
        return
    }

    val parcelFileDescriptor =
        contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?: return

    val inputStream = FileInputStream(parcelFileDescriptor.fileDescriptor)
    val file = File(cacheDir, contentResolver.getFileName(selectedImageUri!!))
    val outputStream = FileOutputStream(file)
    inputStream.copyTo(outputStream)

    progress_bar!!.progress = 0
    val body = UploadRequestBody(file, "image", this)
    MyAPI().uploadImage(
        MultipartBody.Part.createFormData(
            "file",
            file.name,
            body
        ),
        RequestBody.create(MediaType.parse("multipart/form-data"), "json")
    ).enqueue(object : Callback<UploadResponse> {
        override fun onFailure(call: Call<UploadResponse>, t: Throwable) {
            layout_root!!.snackbar(t.message!!)
            progress_bar!!.progress = 0
        }

        override fun onResponse(
            call: Call<UploadResponse>,
            response: Response<UploadResponse>
        ) {
            response.body()?.let {
                layout_root!!.snackbar(it.message)
                progress_bar!!.progress = 100
                classes!!.text = it.data.classes
                layout!!.visibility = View.VISIBLE
                Glide.with(this@MainActivity).load("http://167.172.72.26:1337/"+ it.data.image_after_preprocessing).into(
                    image_view!!
                )
            }
        }
    })

}

override fun onProgressUpdate(percentage: Int) {
    progress_bar!!.progress = percentage
}

companion object {
    const val REQUEST_CODE_PICK_IMAGE = 101
}

Upvotes: 0

Views: 420

Answers (2)

Dr.jacky
Dr.jacky

Reputation: 3547

In case you don't use Crop option, you just need to add:

mGalleryUri?.let { galleryUri ->
                        contentResolver.takePersistableUriPermission(
                            galleryUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
                        )
                    }

https://developer.android.com/training/data-storage/shared/photopicker#persist-media-file-access


I'll change ACTION_GET_CONTENT to ACTION_OPEN_DOCUMENT on the next update.
[And if I could find a way to have both worlds(having crop and let developer use or not use takePersistableUriPermission, I'll update again.]

Upvotes: 0

Arcel V Luceno
Arcel V Luceno

Reputation: 3

This answer is late but it might help others.

I just added .crop() to it like this.

ImagePicker.with(this)
    .crop()
    .provider(ImageProvider.BOTH)
    .setDismissListener {
        Log.d("ImagePicker", "onDismiss");
    }
    .createIntentFromDialog { profileLauncher.launch(it) }

I noticed that the error only persist when using the gallery and adding the .crop() is the only solution to it.

Upvotes: 0

Related Questions