title: java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/**/cache/storage/CAPTURE-20210427_125521.jpg
body: <p>I am developing a flutter app in which I'm using <code>webview_flutter</code> plugin. Now inside the webview I want upload a file from the device. The problem is when I try to select browse button to choose the files from my device (or use Camera directly), I get <code>IllegalArgumentException</code>.</p>
  <p>I found other issues like this but it didn't solve my problem:</p>
  <ul>
  <li><a href="https://stackoverflow.com/questions/42407486/java-lang-illegalargumentexception-failed-to-find-configured-root-that-contains">java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/</a></li>
  <li><a href="https://stackoverflow.com/questions/31345275/android-fileprovider-illegalargumentexception-failed-to-find-configured-root-th">Android: FileProvider IllegalArgumentException Failed to find configured root that contains /data/data/**/files/Videos/final.mp4</a></li>
  <li><a href="https://stackoverflow.com/questions/42516126/fileprovider-illegalargumentexception-failed-to-find-configured-root?rq=1">FileProvider - IllegalArgumentException: Failed to find configured root</a></li>
  </ul>
  <p>Below is the code for the package I'm using:
  (You can also go to this <a href="https://github.com/flutter/plugins/pull/3225/files" rel="nofollow noreferrer">LINK</a> to get the exact code which I'm using)</p>
  <blockquote>
  <p>packages/webview_flutter/android/src/main/AndroidManifest.xml:</p>
  </blockquote>
  <pre><code>&lt;manifest package=&quot;io.flutter.plugins.webviewflutter&quot;
  xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
  &lt;application&gt;
      &lt;activity
          android:name=&quot;io.flutter.plugins.webviewflutter.RequestCameraPermissionActivity&quot;
          android:theme=&quot;@android:style/Theme.Translucent.NoTitleBar.Fullscreen&quot; /&gt;
      &lt;activity
          android:name=&quot;io.flutter.plugins.webviewflutter.FileChooserActivity&quot;
          android:theme=&quot;@android:style/Theme.Translucent.NoTitleBar.Fullscreen&quot; /&gt;
  
      &lt;provider
          android:name=&quot;io.flutter.plugins.webviewflutter.GenericFileProvider&quot;
          android:authorities=&quot;${applicationId}.generic.provider&quot;
          android:exported=&quot;false&quot;
          android:grantUriPermissions=&quot;true&quot;
          &gt;
          &lt;meta-data
              android:name=&quot;android.support.FILE_PROVIDER_PATHS&quot;
              android:resource=&quot;@xml/provider_paths&quot;
              /&gt;
      &lt;/provider&gt;
  &lt;/application&gt;
  </code></pre>
  
  <blockquote>
  <p>packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/Constants.java:</p>
  </blockquote>
  <pre><code>package io.flutter.plugins.webviewflutter;
  
  public class Constants {
    static final String ACTION_REQUEST_CAMERA_PERMISSION_FINISHED =
        &quot;action_request_camera_permission_denied&quot;;
    static final String ACTION_FILE_CHOOSER_FINISHED = &quot;action_file_chooser_completed&quot;;
  
    static final String EXTRA_TITLE = &quot;extra_title&quot;;
    static final String EXTRA_ACCEPT_TYPES = &quot;extra_types&quot;;
    static final String EXTRA_SHOW_VIDEO_OPTION = &quot;extra_show_video_option&quot;;
    static final String EXTRA_SHOW_IMAGE_OPTION = &quot;extra_show_image_option&quot;;
    static final String EXTRA_FILE_URIS = &quot;extra_file_uris&quot;;
    static final String EXTRA_ALLOW_MULTIPLE_FILES = &quot;extra_allow_multiple_files&quot;;
  
    static final String WEBVIEW_STORAGE_DIRECTORY = &quot;storage&quot;;
  }
  </code></pre>
  <blockquote>
  <p>packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FileChooserActivity.java:</p>
  </blockquote>
  <pre><code>package io.flutter.plugins.webviewflutter;
  
  import static io.flutter.plugins.webviewflutter.Constants.ACTION_FILE_CHOOSER_FINISHED;
  import static io.flutter.plugins.webviewflutter.Constants.EXTRA_ACCEPT_TYPES;
  import static io.flutter.plugins.webviewflutter.Constants.EXTRA_ALLOW_MULTIPLE_FILES;
  import static io.flutter.plugins.webviewflutter.Constants.EXTRA_FILE_URIS;
  import static io.flutter.plugins.webviewflutter.Constants.EXTRA_SHOW_IMAGE_OPTION;
  import static io.flutter.plugins.webviewflutter.Constants.EXTRA_SHOW_VIDEO_OPTION;
  import static io.flutter.plugins.webviewflutter.Constants.EXTRA_TITLE;
  import static io.flutter.plugins.webviewflutter.Constants.WEBVIEW_STORAGE_DIRECTORY;
  
  import android.app.Activity;
  import android.content.Intent;
  import android.database.Cursor;
  import android.net.Uri;
  import android.os.Bundle;
  import android.provider.MediaStore;
  import android.provider.OpenableColumns;
  import android.util.Log;
  import androidx.annotation.Nullable;
  import androidx.core.content.FileProvider;
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Date;
  
  public class FileChooserActivity extends Activity {
  
    private static final int FILE_CHOOSER_REQUEST_CODE = 12322;
    private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(&quot;yyyyMMdd_HHmmss&quot;);
  
    // List of Uris that point to files where there MIGHT be the output of the capture. At most one of these can be valid
    private final ArrayList&lt;Uri&gt; potentialCaptureOutputUris = new ArrayList&lt;&gt;();
  
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      showFileChooser(
          getIntent().getBooleanExtra(EXTRA_SHOW_IMAGE_OPTION, false),
          getIntent().getBooleanExtra(EXTRA_SHOW_VIDEO_OPTION, false));
    }
  
    private void showFileChooser(boolean showImageIntent, boolean showVideoIntent) {
      Intent getContentIntent = createGetContentIntent();
      Intent captureImageIntent =
          showImageIntent ? createCaptureIntent(MediaStore.ACTION_IMAGE_CAPTURE, &quot;jpg&quot;) : null;
      Intent captureVideoIntent =
          showVideoIntent ? createCaptureIntent(MediaStore.ACTION_VIDEO_CAPTURE, &quot;mp4&quot;) : null;
  
      if (getContentIntent == null &amp;&amp; captureImageIntent == null &amp;&amp; captureVideoIntent == null) {
        // cannot open anything: cancel file chooser
        sendBroadcast(new Intent(ACTION_FILE_CHOOSER_FINISHED));
        finish();
      } else {
        ArrayList&lt;Intent&gt; intentList = new ArrayList&lt;&gt;();
  
        if (getContentIntent != null) {
          intentList.add(getContentIntent);
        }
  
        if (captureImageIntent != null) {
          intentList.add(captureImageIntent);
        }
        if (captureVideoIntent != null) {
          intentList.add(captureVideoIntent);
        }
  
        Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
        chooserIntent.putExtra(Intent.EXTRA_TITLE, getIntent().getStringExtra(EXTRA_TITLE));
  
        chooserIntent.putExtra(Intent.EXTRA_INTENT, intentList.get(0));
        intentList.remove(0);
        if (intentList.size() &gt; 0) {
          chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Intent[0]));
        }
  
        startActivityForResult(chooserIntent, FILE_CHOOSER_REQUEST_CODE);
      }
    }
  
    private Intent createGetContentIntent() {
      Intent filesIntent = new Intent(Intent.ACTION_GET_CONTENT);
  
      if (getIntent().getBooleanExtra(EXTRA_ALLOW_MULTIPLE_FILES, false)) {
        filesIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
      }
  
      String[] acceptTypes = getIntent().getStringArrayExtra(EXTRA_ACCEPT_TYPES);
  
      if (acceptTypes.length == 0 || (acceptTypes.length == 1 &amp;&amp; acceptTypes[0].length() == 0)) {
        // empty array or only 1 empty string? -&gt; accept all types
        filesIntent.setType(&quot;*/*&quot;);
      } else if (acceptTypes.length == 1) {
        filesIntent.setType(acceptTypes[0]);
      } else {
        // acceptTypes.length &gt; 1
        filesIntent.setType(&quot;*/*&quot;);
        filesIntent.putExtra(Intent.EXTRA_MIME_TYPES, acceptTypes);
      }
  
      return (filesIntent.resolveActivity(getPackageManager()) != null) ? filesIntent : null;
    }
  
    private Intent createCaptureIntent(String type, String fileFormat) {
      Intent captureIntent = new Intent(type);
      if (captureIntent.resolveActivity(getPackageManager()) == null) {
        return null;
      }
  
      // Create the File where the output should go
      Uri captureOutputUri = getTempUri(fileFormat);
      potentialCaptureOutputUris.add(captureOutputUri);
  
      captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, captureOutputUri);
  
      return captureIntent;
    }
  
    private File getStorageDirectory() {
      File imageDirectory = new File(getCacheDir(), WEBVIEW_STORAGE_DIRECTORY);
      if (!imageDirectory.exists() &amp;&amp; !imageDirectory.mkdir()) {
        Log.e(&quot;WEBVIEW&quot;, &quot;Unable to create storage directory&quot;);
      }
      return imageDirectory;
    }
  
    private Uri getTempUri(String format) {
      String fileName = &quot;CAPTURE-&quot; + simpleDateFormat.format(new Date()) + &quot;.&quot; + format;
      File file = new File(getStorageDirectory(), fileName);
      return FileProvider.getUriForFile(
          this, getApplicationContext().getPackageName() + &quot;.generic.provider&quot;, file);
    }
  
    private String getFileNameFromUri(Uri uri) {
      Cursor returnCursor = getContentResolver().query(uri, null, null, null, null);
      assert returnCursor != null;
      int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
      returnCursor.moveToFirst();
      String name = returnCursor.getString(nameIndex);
      returnCursor.close();
      return name;
    }
  
    private Uri copyToLocalUri(Uri uri) {
      File destination = new File(getStorageDirectory(), getFileNameFromUri(uri));
  
      try (InputStream in = getContentResolver().openInputStream(uri);
          OutputStream out = new FileOutputStream(destination)) {
        byte[] buffer = new byte[1024];
        int len;
        while ((len = in.read(buffer)) != -1) {
          out.write(buffer, 0, len);
        }
        return FileProvider.getUriForFile(
            this, getApplicationContext().getPackageName() + &quot;.generic.provider&quot;, destination);
      } catch (IOException e) {
        Log.e(&quot;WEBVIEW&quot;, &quot;Unable to copy selected image&quot;, e);
        e.printStackTrace();
        return null;
      }
    }
  
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (requestCode == FILE_CHOOSER_REQUEST_CODE) {
        Intent fileChooserFinishedIntent = new Intent(ACTION_FILE_CHOOSER_FINISHED);
        if (resultCode == Activity.RESULT_OK) {
          if (data != null &amp;&amp; (data.getDataString() != null || data.getClipData() != null)) {
            if (data.getDataString() != null) {
              // single result from file browser OR video from camera
              Uri localUri = copyToLocalUri(data.getData());
              if (localUri != null) {
                fileChooserFinishedIntent.putExtra(
                    EXTRA_FILE_URIS, new String[] {localUri.toString()});
              }
            } else if (data.getClipData() != null) {
              // multiple results from file browser
              int uriCount = data.getClipData().getItemCount();
              String[] uriStrings = new String[uriCount];
  
              for (int i = 0; i &lt; uriCount; i++) {
                Uri localUri = copyToLocalUri(data.getClipData().getItemAt(i).getUri());
                if (localUri != null) {
                  uriStrings[i] = localUri.toString();
                }
              }
              fileChooserFinishedIntent.putExtra(EXTRA_FILE_URIS, uriStrings);
            }
          } else {
            // image result from camera (videos from the camera are handled above, but this if-branch could handle them too if this varies from device to device)
            for (Uri captureOutputUri : potentialCaptureOutputUris) {
              try {
                // just opening an input stream (and closing immediately) to test if the Uri points to a valid file
                // if it's not a real file, the below catch-clause gets executed and we continue with the next Uri in the loop.
                getContentResolver().openInputStream(captureOutputUri).close();
                fileChooserFinishedIntent.putExtra(
                    EXTRA_FILE_URIS, new String[] {captureOutputUri.toString()});
                // leave the loop, as only one of the potentialCaptureOutputUris is valid and we just found it
                break;
              } catch (IOException ignored) {
              }
            }
          }
        }
        sendBroadcast(fileChooserFinishedIntent);
        finish();
      } else {
        super.onActivityResult(requestCode, resultCode, data);
      }
    }
  }
  </code></pre>
  <blockquote>
  <p>packages/webview_flutter/android/src/main/res/values/strings.xml:</p>
  </blockquote>
  <pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
  &lt;resources&gt;
      &lt;string name=&quot;webview_file_chooser_title&quot;&gt;Choose a file&lt;/string&gt;
      &lt;string name=&quot;webview_image_chooser_title&quot;&gt;Choose an image&lt;/string&gt;
      &lt;string name=&quot;webview_video_chooser_title&quot;&gt;Choose a video&lt;/string&gt;
  &lt;/resources&gt;
  </code></pre>
  <blockquote>
  <p>packages/webview_flutter/android/src/main/res/xml/provider_paths.xml:</p>
  </blockquote>
  <pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
  &lt;paths&gt;
      &lt;cache-path name=&quot;storage&quot;/&gt;
  &lt;/paths&gt;
  </code></pre>
  <p>The app is crashing with this error:</p>
  <pre><code>I/Timeline(26709): Timeline: Activity_launch_request time:162255045 intent:Intent { flg=0x10000000 cmp=com.XXXX(Package)/io.flutter.plugins.webviewflutter.FileChooserActivity (has extras) }
  D/OneSignal(26709): curActivity is NOW: null
  W/ActivityThread(26709): handleWindowVisibility: no activity for token android.os.BinderProxy@1811995
  D/AndroidRuntime(26709): Shutting down VM
  E/AndroidRuntime(26709): FATAL EXCEPTION: main
  E/AndroidRuntime(26709): Process: com.XXXX, PID: 26709
  E/AndroidRuntime(26709): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.XXXX/io.flutter.plugins.webviewflutter.FileChooserActivity}: java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.XXXX(Package)/cache/storage/CAPTURE-20210426_203521.jpg
  E/AndroidRuntime(26709):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2946)
  E/AndroidRuntime(26709):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3081)
  E/AndroidRuntime(26709):    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
  E/AndroidRuntime(26709):    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
  E/AndroidRuntime(26709):    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
  E/AndroidRuntime(26709):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1831)
  E/AndroidRuntime(26709):    at android.os.Handler.dispatchMessage(Handler.java:106)
  E/AndroidRuntime(26709):    at android.os.Looper.loop(Looper.java:201)
  E/AndroidRuntime(26709):    at android.app.ActivityThread.main(ActivityThread.java:6810)
  E/AndroidRuntime(26709):    at java.lang.reflect.Method.invoke(Native Method)
  E/AndroidRuntime(26709):    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
  E/AndroidRuntime(26709):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
  E/AndroidRuntime(26709): Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.XXXX(Package)/cache/storage/CAPTURE-20210426_203521.jpg
  E/AndroidRuntime(26709):    at androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:744)
  E/AndroidRuntime(26709):    at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:418)
  E/AndroidRuntime(26709):    at io.flutter.plugins.webviewflutter.FileChooserActivity.getTempUri(FileChooserActivity.java:138)
  E/AndroidRuntime(26709):    at io.flutter.plugins.webviewflutter.FileChooserActivity.createCaptureIntent(FileChooserActivity.java:119)
  E/AndroidRuntime(26709):    at io.flutter.plugins.webviewflutter.FileChooserActivity.showFileChooser(FileChooserActivity.java:54)
  E/AndroidRuntime(26709):    at io.flutter.plugins.webviewflutter.FileChooserActivity.onCreate(FileChooserActivity.java:46)
  E/AndroidRuntime(26709):    at android.app.Activity.performCreate(Activity.java:7224)
  E/AndroidRuntime(26709):    at android.app.Activity.performCreate(Activity.java:7213)
  E/AndroidRuntime(26709):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
  E/AndroidRuntime(26709):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2926)
  E/AndroidRuntime(26709):    ... 11 more
  D/libcrashlytics(26709): Initializing libcrashlytics version 3.0.0
  D/libcrashlytics(26709): Initializing native crash handling successful.
  </code></pre>
  <p>Can you help me with what I may be missing?</p>