This error occurs ONLY when an image was choosed from Photo Picker on android 13 (on versions without Photo Picker all works!).
What does code:
User picks image from Photo Picker.
Get image's uri and save file in body, there all is working too:
File imgFile = FilesHelper.INSTANCE.getFileFromUri(this, imgUri);
postBody.setPhoto(imgFile);
@Throws(Exception::class)
fun getFileFromUri(context: Context, uri: Uri): File? {
var path: String? = null
if ("content".equals(uri.scheme, ignoreCase = true)) {
path = getDataColumn(context, uri, null, null)
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
path = uri.path
}
return if (!path.isNullOrEmpty()) File(path) else null
}
private fun getDataColumn(context: Context, uri: Uri,
selection: String?, selectionArgs: Array<String?>?): String? {
var cursor: Cursor? = null
val column = MediaStore.Images.Media.DATA
val projection = arrayOf(column)
try {
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
if (cursor != null && cursor.moveToFirst()) {
val column_index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(column_index)
}
} finally {
cursor?.close()
}
return null
}
But when body is sending as multipart,
final Map<String, RequestBody> multipart = new HashMap<>(2);
multipart.put("product",
RequestBody.create(MediaType.parse("application/json"),
BaseApplication.getGson().toJson(postBody)));
multipart.put("image\"; filename=\"%1.jpg\"",
RequestBody.create(MediaType.parse("image/jpeg"),
postBody.getPhoto())); // type File
....
serverApi.sendBody(multipart);
....
a warning was shown in logCat:
*
/sdcard/.transforms/synthetic/picker/0/com.android.providers.media.photopicker/media/1000000019.jpg: open failed: EFAULT (Bad address)*
and then retrofit/okhttp throws exception.
Retrofit version "com.squareup.retrofit2:retrofit:2.9.0"
Permissions in AndroidManifest, which are given before picking image:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--Android 13 permissions-->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
And
android:requestLegacyExternalStorage="true"
in <application> too.
Asking permissions:
if (VERSION.SDK_INT >= 33) arrayOf(Manifest.permission.READ_MEDIA_IMAGES) else arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
Can I get and send that image without using MANAGE_EXTERNAL_STORAGE permission? Because application distributes via Google Play and is not files manager or something like that. Maybe I should copy file in app's internal files dir or what?
Well, found solution: grant read uri permission
private void onImagePicked(Uri imgUri){
if(imgUri!=null) {
try {
grantUriPermission(getPackageName(),imgUri,Intent.FLAG_GRANT_READ_URI_PERMISSION);
File imgFile = FilesHelper.INSTANCE.getFileFromUri(this, imgUri);
postBody.setPhoto(imgFile);
} catch (Exception e) {
...
}
}
}