Search code examples
androidkotlinmobileandroid-cameraandroid-camera-intent

Failed to find configured root that contains when Intent is in fragment


There are many questions and answers about this topic on the internet but unfortunately it didnt solve my problem.

I get a error every time I try to intent a Camera for a picture of video recording within my Fragment. The path where I want to save those files are in /data/data/com.example.testing/files/*

The error that I always get is: Failed to find configured root that "contains/data/data/com.example.testing/files/test.jpg" and "Failed to find configured root that contains/data/data/com.example.testing/files/test.mp4"

The complete error log:

2020-12-16 00:14:32.093 6473-6473/com.example.testing E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.testing, PID: 6473
    java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.example.testing/files/test.jpg
        at androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:744)
        at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:418)
        at com.example.testing.fragments.InvitesCheck.capturePhoto(InvitesCheck.kt:141)
        at com.example.testing.fragments.InvitesCheck.access$capturePhoto(InvitesCheck.kt:32)
        at com.example.testing.fragments.InvitesCheck$onViewCreated$1.onClick(InvitesCheck.kt:53)
        at android.view.View.performClick(View.java:7192)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:992)
        at android.view.View.performClickInternal(View.java:7166)
        at android.view.View.access$3500(View.java:824)
        at android.view.View$PerformClick.run(View.java:27592)
        at android.os.Handler.handleCallback(Handler.java:888)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:213)
        at android.app.ActivityThread.main(ActivityThread.java:8178)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)

I tried different setups but unfortunately no luck.

This is my Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testing">
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-feature android:name="android.hardware.camera" />

    <application
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Testing">

        <activity
            android:name=".MainActivity"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

    </application>

</manifest>

I am using the following functions to call the camera:

private fun capturePhoto() {
    val file = File(requireContext().filesDir.path, "test.jpg")
    val uri = FileProvider.getUriForFile(requireActivity(), BuildConfig.APPLICATION_ID.toString() + ".provider", file)
    val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
    startActivityForResult(intent, REQUEST_CODE)
}

private fun captureVideo() {
    val file = File(requireContext().filesDir.path, "test.mp4")
    val uri = FileProvider.getUriForFile(requireActivity(), BuildConfig.APPLICATION_ID.toString() + ".provider", file)
    val intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
    startActivityForResult(intent, REQUEST_VIDEO)
}

xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="external_files" path="."/>
</paths>

What am I doing wrong?

Thank you in advance.


Solution

  • Reading up on this question, it seems that you should be using Context.getExternalFilesDir() instead of Context.getFilesDir()` whenever you're creating the File to which to write to.

    This would end up looking something like this:

    private fun capturePhoto() {
        val file = File(requireContext().getExternalFilesDir(null).path, "test.jpg")
        val uri = FileProvider.getUriForFile(requireActivity(), BuildConfig.APPLICATION_ID.toString() + ".provider", file)
        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
        startActivityForResult(intent, REQUEST_CODE)
    }
    

    BONUS: I would recommend you take a look at the MediaStore class if you're planning on making a media-oriented app. Here's an official intro for it.