Filipe Ramos
Filipe Ramos

Reputation: 1795

Take picture and save to gallery

I've spend hours looking into this issue, and I've found no solution (on StackOverflow or otherwise). My app is targeting API 30 and the minSskVersion is 29. I'm following this tutorial: https://developer.android.com/training/camera/photobasics

I have a button on my activity that opens the camera using an intent:

fun takePhoto() {
    Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
        takePictureIntent.resolveActivity(packageManager)?.also {
              startActivityForResult(takePictureIntent, CAMERA_REQUEST)
        }
    }
}

But I also want to save the picture on the device gallery. So I changed my takePhoto() method to:

fun takePhoto() {
    Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
        takePictureIntent.resolveActivity(packageManager)?.also {
            val photoFile: File? = try {
                createImageFile()
            } catch (ex: IOException) {
                ex.printStackTrace()
                null
            }

            photoFile?.also {
                try {
                    val photoURI: Uri = FileProvider.getUriForFile(
                        this,
                        "net.filiperamos.photogrid.provider",
                        it
                    )

                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                } catch (ex: IllegalArgumentException) {
                    Log.d(TAG, "Could not get file URI.")
                    ex.printStackTrace()
                }

                startActivityForResult(takePictureIntent, CAMERA_REQUEST)
            }
        }
    }
}

and added the createImageFile() method:

private fun createImageFile(): File {
    val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
    val filename = "image_$timeStamp"
    val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)

    return File.createTempFile(filename, ".jpg", storageDir).apply {
        currentPhotoPath = absolutePath // Save path for later use
    }
}

My Manifest has the camera use and the external writing permission:

<uses-feature
    android:name="android.hardware.camera"
    android:required="false" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

I added a provider indie the application tag:

    <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/file_paths" />
    </provider>

and I created the file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-files-path
        name="my_images"
        path="Android/data/net.ramos.photos/files/Pictures/" />
</paths>

When I run this code on my device, I get an exception when running FileProvider.getUriForFile():

java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/net.ramos.photos/files/Pictures/image_20200823_1415398042919497737944663.jpg

And if I change my file_paths.xml file, replacing external-files-pathfor external-path, the error goes away, but no image is stored nowhere.

What am I missing?

Upvotes: 1

Views: 1309

Answers (1)

Arun123
Arun123

Reputation: 118

Add the following line in your manifest file as an attribute of 'application' tag,

android:requestLegacyExternalStorage="true"

this should solve the problem you are facing and the exception should go away.

Upvotes: 1

Related Questions