Access permission denied to external file on Android 10

Viewed 4399

My app is targetSdkVersion = 29

I take a photo and it save at path:

src = /storage/emulated/0/DCIM/Camera/IMG_20201120_091943.jpg

Then I want to copy this image to internal storage using FileInputStream/FileOutputStream. Although, my app has WRITE/READ storage permission, but when I code

InputStream inputStream = FileInputStream(src)

I received a FileNotFoundException (open failed: EACCES permission denied).

Anyone have same problem?

Note: I don't want to fix this problem by using a option AndroidManifest.xml because it is temp

android:requestLegacyExternalStorage="true"

3 Answers

When your targetSdkVersion >= 29 then you have to use ScopedStorage, see the docs: https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage

So the short answer is you can't really do this. You should use MediaStore API to write shared storage ("/storage/emulated/0/DCIM/Camera/IMG_20201120_091943.jpg" is not private to your app, so the rules apply) if your targetSdkVersion is 29

Here's how you can use MediaStoreApi to insert your image to the user's images: https://stackoverflow.com/a/56990305/5601663

Also if you really just want to save the file, so that it is only available inside your application, then you don't need to use MediaStoreApi see this article on how you can save inside your apps private directory: https://medium.com/@maksymilian.wojcik/android-saving-files-in-internal-storage-image-from-byte-array-etc-dd7d1b86d309

Edit: you can use of course the requestLegacyExternalStorage flag on your manifest, but you've already said that you don't want to use that

Edit2: I see now that you wanted to read from the shared storage. That too won't work, because you need to use either the Storage Access Framework, or the Media Store to read from there, if your targetSdkVersion >= 29. So for that case follow the instructions described here: https://developer.android.com/training/data-storage/use-cases#import-image-media

On Android 10 you can't use File API to access files in shared storage, unfortunately, the Android doc is not consistent about this, you can find it here thought

To work around this use Uri API on Android 10, although this is not an issue in Android 11 forward

val uri = ContentUris.withAppendedId(MediaStore.Image.Media.EXTERNAL_CONTENT_URI, id)

applicationContext.contentResolver.openInputStream(uri).use { stream ->
   // do your thing here
}

Note: You can still use File API on any files that your app owns

I show detail my code using FileInputStream/FileOutputStream

src = /storage/emulated/0/DCIM/Camera/IMG_20201120_091943.jpg

dst = /storage/emulated/0/Android/data/my_app/files/Pictures/IMG_20201118_113434.jpg

src is place where save photo taken, dst is place where I want to copy file src to this

public void copy(String src, String dst) {
        try {
            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(src));
            OutputStream outPutStream = new FileOutputStream(dst);
            int len;
            byte[] buf = new byte[1024];
            while ((len = bufferedInputStream.read(buf)) > 0) {
                outPutStream.write(buf, 0, len);
            }

            outPutStream.flush();
            outPutStream.close();
            bufferedInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

FileNotFoundException (open failed: EACCES permission denied) at line:

BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(src));

Related