I need help with this problem since I'm new to Android.
My app support JellyBean (16) up to Oreo (26).
I have an UploadService that requires openInputStream()
to upload data because the new behavior in Nougat.
This code works fine in Marshmallow and below, but always give me SecurityException
crash on Nougat. And it crashes on the line where openInputStream()
is called with error:
java.lang.SecurityException: Permission Denial: reading com.miui.gallery.provider.GalleryOpenProvider uri content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FDCIM%2FCamera%2FIMG_20171008_182834.jpg from pid=30846, uid=10195 requires the provider be exported, or grantUriPermission()
The file uri could be from various app (gallery, camera, etc). I've narrowed down the problem to uri that comes from ACTION_GET_CONTENT
intent (anything that comes from camera intent or MediaRecorder works fine).
I think it's because the uri lost its permission when passed into the service, but adding Intent.FLAG_GRANT_WRITE_URI_PERMISSION
and Intent.FLAG_GRANT_READ_URI_PERMISSION
doesn't help.
Also tried adding FLAG_GRANT_PERSISTABLE_URI_PERMISSION
flag, but it still crashes and getContentResolver().takePersistableUriPermission()
causes another SecurityException
crash saying the said uri hasn't been granted persistable uri...
UploadService.java
//.......... code to prepare for upload
if ( contentResolver != null && schemeContentFile ) {
mMime = UtilMedia.getMime(this, uri);
try {
InputStream is = contentResolver.openInputStream(uri);
byte[] mBytes = getBytes(is);
Bundle fileDetail = UtilMedia.getFileDetailFromUri(this, uri);
Log.d("AndroidRuntime", TAG + " " + mMime + " " + UtilToString.bundleToString(fileDetail) + " imageFile " + mFile);
currTitle = fileDetail.getString(OpenableColumns.DISPLAY_NAME, "");
MediaType type = MediaType.parse(mMime);
requestFile = RequestBody.create(type, mBytes);
} catch ( IOException e ) {
e.printStackTrace();
} catch ( SecurityException e ) {
e.printStackTrace();
}
}
//............continue to upload
Thank You in advance.
EDIT (Additional Info)
In case this is important. The activity calling the service is calling finish()
after it sends all the required data to the service, letting user to use the app, while the upload resumed in the background (with notification to tell user). And also, the upload works based on queue, and user can choose to upload multiple files in the activity. The first file always gets uploaded, but the files after always return with the crash.