Search code examples
javaandroidpermissionscameraprovider

open failed: EACCES (Permission denied) while using a FileProvider in onActivityResult


I am trying to get a recently recorded Video in onActivityResult. But I don't understand how this Content Provider works. I am not used to program in Java for Android so it might be a simple thing but I can't solve it myself.

The Question is only how to get the content://media/external/video/media/17877 to a local file using the provider in the app folder where no extra access is needed

This is the Codepart I am Debugging:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    ....
    } else if (requestCode == CAMERA_REQUEST_VIDEO) {
        if (resultCode == Activity.RESULT_OK && data != null) {
    ....
            Uri selectedMediaUri = data.getData();
            String strMediaFile = getRealPathFromURI(getApplicationContext(),selectedMediaUri);
            Log.d("App","got link:"+selectedMediaUri+" File:"+strMediaFile);
            File fileCameraTemp = new File(strCameraTempFile);
            File fileCameraResult = new File(strMediaFile);
            Uri sharedFileUri = FileProvider.getUriForFile(this, "de.xyz.app.fileprovider", fileCameraResult);
            InputStream is = getContentResolver().openInputStream(sharedFileUri);
            FileOutputStream fos = new FileOutputStream(fileCameraTemp);

            byte[] buf = new byte[1024];
            int len;
            while ((len = is.read(buf)) > 0) {
                fos.write(buf, 0, len);
            }
            is.close();
            fos.close();
    ....
}

I am trying to store the Video File to a local accessible File.

The getRealPathFromURI function:

public String getRealPathFromURI(Context context, Uri contentUri) {
  Cursor cursor = null;
  try {
    String[] proj = { MediaStore.Images.Media.DATA };
    cursor = context.getContentResolver().query(contentUri,  proj, null, null, null);
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
  } finally {
    if (cursor != null) {
      cursor.close();
    }
  }
}

So the log output I get is following:

App: onActivityResult
D App: CAMERA_REQUEST_VIDEO
D App: No valid strCameraTempFile:/storage/emulated/0/cameraresult.mp4 -> using data
D App: got data
D App: got link:content://media/external/video/media/17877 File:/storage/emulated/0/DCIM/Camera/20230824_113912.mp4
W System.err: java.io.FileNotFoundException: open failed: EACCES (Permission denied)
W System.err:   at android.os.ParcelFileDescriptor.openInternal(ParcelFileDescriptor.java:315)
W System.err:   at android.os.ParcelFileDescriptor.open(ParcelFileDescriptor.java:220)
W System.err:   at androidx.core.content.FileProvider.openFile(FileProvider.java:566)
W System.err:   at android.content.ContentProvider.openAssetFile(ContentProvider.java:1733)
W System.err:   at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1915)
W System.err:   at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1982)
W System.err:   at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:511)
W System.err:   at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1701)
W System.err:   at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1517)
W System.err:   at android.content.ContentResolver.openInputStream(ContentResolver.java:1201)
W System.err:   at de.x.y.App.onActivityResult(App.java:484)
W System.err:   at android.app.Activity.dispatchActivityResult(Activity.java:8300)
W System.err:   at android.app.ActivityThread.deliverResults(ActivityThread.java:5353)
W System.err:   at android.app.ActivityThread.handleSendResult(ActivityThread.java:5401)
W System.err:   at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
W System.err:   at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
W System.err:   at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
W System.err:   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2267)
W System.err:   at android.os.Handler.dispatchMessage(Handler.java:107)
W System.err:   at android.os.Looper.loop(Looper.java:237)
W System.err:   at android.app.ActivityThread.main(ActivityThread.java:8167)
W System.err:   at java.lang.reflect.Method.invoke(Native Method)
W System.err:   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
W System.err:   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)

I have a Provider in my Android Manifest:

    <provider android:name="androidx.core.content.FileProvider" android:authorities="v.fileprovider" android:exported="false" android:grantUriPermissions="true">

        <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
    </provider>

with following Configuration:

<?xml version="1.0" encoding="utf-8"?>
<paths>
     <external-files-path name="images" path="Pictures"/>
     <cache-path name="cache" path="."/>
     <files-path name="files" path="."/>
     <external-path name="external" path="." />
     <cache-path name="cache" path="." />
     <external-cache-path name="external_cache" path="." />
</paths>

I don't know what to do to make this work and hope that somebody can help me with this

The strCameraTempFile is a File in the local App Folder.


Solution

  • The correction mentioned by @blackapps in the comments (although he became a little bit insolent) was the key. After he read my post especially the logcat output in detail he found what I did not read precise enough. It was something not shown in my code snipped above.

    I missed that the strCameraTempFile was filled with a not accessible path (I changed it while debugging before using the Fileprovider). So the above posted code is correct but the input for strCameraTempFile should be a reachable path e.g. like getFilesDir().getAbsolutePath().

    Hope it helps someone.