I have the following function to select an image and display it in an ImageView (only relevant code):
Start gallery picker:
fun selectPic(view: View) {
val intent = Intent(Intent.ACTION_PICK);
intent.type = "image/*";
startActivityForResult(intent, 1000);
}
Get selected image from gallery picker:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == 1000) {
println("DATA " + data?.data)
// SET PATH TO GLOBAL VARIABLE
uri_path = data?.data;
findViewById<ImageView>(R.id.selected_image).setImageURI(data?.data);
}
}
Then I use this piece of code to retrieve the image again so I can upload the file to a server:
...
val file: File = File(getRealPathFromURI(fileUri));
...
getRealPathFromUri()
fun getRealPathFromURI(uri: Uri?): String? {
val cursor: Cursor? = contentResolver.query(uri!!, null, null, null, null)
if (cursor == null) {
return null;
}
cursor.moveToFirst()
val idx: Int = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA)
return cursor.getString(idx)
}
uploadFile
private fun uploadFile(fileUri: Uri) {
// create upload service client
val service: FileUploadService =
ServiceGenerator.createService(FileUploadService::class.java)
// uri_path IS THE GLOBAL VARIABLE WITH VALUE data?.data
val file: File = File(uri_path.toString());
// create RequestBody instance from file
val requestFile = RequestBody.create(
MediaType.parse(contentResolver.getType(fileUri)),
file
)
// MultipartBody.Part is used to send also the actual file name
val body =
MultipartBody.Part.createFormData("file", file.name, requestFile)
// add another part within the multipart request
val descriptionString = "hello, this is description speaking"
val description = RequestBody.create(
MultipartBody.FORM, descriptionString
)
// finally, execute the request
val call: Call<ResponseBody?>? = service.upload(description, body)
if (call != null) {
call.enqueue(object : Callback<ResponseBody?> {
override fun onResponse(
call: Call<ResponseBody?>?,
response: Response<ResponseBody?>?
) {
Log.v("Upload", "success")
println("RESPONSE " + response);
}
override fun onFailure(call: Call<ResponseBody?>?, t: Throwable) {
t.message?.let { Log.e("Upload error:", it) }
}
})
}
}
Relevant parts of my AndroidManifext.xml:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="ANDROID.PERMISSION.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="ANDROID.PERMISSION.WRITE_EXTERNAL_STORAGE"/>
<application
...
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true">
...
The weird issue is that it works for some files. Example of file that works:
I/System.out: URI content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F64/ORIGINAL/NONE/image%2Fjpeg/1462875550
This file works perfectly and uploads!
But this file gives an error:
E/Upload error:: /storage/emulated/0/Pictures/IMG_20210518_151857.jpg: open failed: EACCES (Permission denied)
Error: open failed: EACCES (Permission denied)
.
Why is the permission denied for this file? I do have the correct requirements in my AndroidManifext.xml?