Search code examples
androidkotlinandroid-imageandroid-fileandroid-thumbnail

Able to store image to a pat but unable to access it using `File` for Thumbnail Creation


I am able to store an image and display it ImageView using the same filePath but get an error when trying to access it for thumbnail creation using ThumbnailUtils

I have a fragment, That captures the image using ActivityResultContract

class TakePictureWithUriReturnContract : ActivityResultContract<Uri, Pair<Boolean, Uri>>() {
    private lateinit var imageUri: Uri

    @CallSuper
    override fun createIntent(context: Context, input: Uri): Intent {
        imageUri = input
        return Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, input)
    }

    override fun getSynchronousResult(
        context: Context,
        input: Uri
    ): SynchronousResult<Pair<Boolean, Uri>>? = null

    @Suppress("AutoBoxing")
    override fun parseResult(resultCode: Int, intent: Intent?): Pair<Boolean, Uri> {
        return (resultCode == Activity.RESULT_OK) to imageUri
    }
}

The above mentioned code is used to handle the contract

val photoFile = File.createTempFile(
            "IMG_",
            ".jpg",
            requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        )

        val uri = FileProvider.getUriForFile(
            requireContext(),
            "${requireContext().packageName}.fileprovider",
            photoFile
        )

        sampleActivityRes.launch(uri)

This method is used to launch the Contract and I am able to get the URI successfully.

I am also able to view the image by setting it to ImageView.

But when I try to access it for thumbnail creation using

private fun generateImageThumbnail(imagePath: String): Bitmap {
        val THUMB_SIZE = 64

        val cancellationToken = CancellationSignal()


        return ThumbnailUtils.createImageThumbnail(
            File(imagePath),
            Size(THUMB_SIZE, THUMB_SIZE),
            cancellationToken
        )
    }

I get java.io.FileNotFoundException exception.

My file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="my_images"
        path="Android/data/com.example.name/files/Pictures" />
    <external-path
        name="external"
        path="." />
    <external-files-path
        name="external_files"
        path="." />
    <cache-path
        name="cache"
        path="." />
    <external-cache-path
        name="external_cache"
        path="." />
    <files-path
        name="files"
        path="." />
    <files-path
        name="images"
        path="." />
</paths>

Android Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

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

    <uses-feature android:name="android.hardware.camera.any" />
    <uses-feature android:name="android.hardware.location.gps" />
    <uses-feature android:name="android.hardware.location.network" />

    <application
        android:name=".TripMemoryApp"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:grantUriPermissions="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:requestLegacyExternalStorage="true"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.TripMemory"
        tools:targetApi="31">

        <provider
            android:name="com.android.tripmemory.utils.MyFileProvider"
            android:authorities="com.android.tripmemory.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
        <!--
             TODO: Before you run your application, you need a Google Maps API key.

             To get one, follow the directions here:

                https://developers.google.com/maps/documentation/android-sdk/get-api-key

             Once you have your API key (it starts with "AIza"), define a new property in your
             project's local.properties file (e.g. MAPS_API_KEY=Aiza...), and replace the
             "YOUR_API_KEY" string in this file with "${MAPS_API_KEY}".
        -->
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="AIzaSyAriNq0SqdYMLgBkShF7E0xaPrGpMf4YZ8" />

        <activity
            android:name=".ui.MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>

sampleResActivity

val sampleActivityRes = registerForActivityResult(
        TakePictureWithUriReturnContract()
    ) { (isSuccess, imageURI) ->
        if (isSuccess) {
            Log.d(LOG_TAG, "Image URI: $imageURI")
            binding.sampleImage.bringToFront()
            binding.sampleImage.setImageURI(imageURI)

            navigateToImagePreview(
                imageURI = imageURI.toString(),
                pathId = viewModel.pathInstance.id
            )
        }
    }

Solution

  • Thanks to @blackapps

    The issue was that the imagePath in generateImageThumbnail was a Schema instead of being an URI/ path.

    It would work if we pass the absolutePath of the file

    so the change would be calling generateImageThumbnail(photoFile.absolutePath) with the absolute path of the File

    val photoFile = File.createTempFile(
                "IMG_",
                ".jpg",
                requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
            )
    
    generateImageThumbnail(photoFile.absolutePath)