Showing media file in gallery

490 Views Asked by At

I am downloading file from my server. Due to Environment.getExternalStorageDirectory() is deprecated To improve user privacy, direct access to shared/external storage devices I am saving the video file to the app folder (Android/data/com.myapp/Videos) using getExternalFilesDir.

What I need is this folder (Videos) will be visible in the gallery, or the file will be visible, either way. But my code does not seem to work:

    val mainPath = requireActivity().getExternalFilesDir(null)!!.path + "/"
    val path = "$mainPath/Videos/clip1.mp4"

    val values = ContentValues(3)
    values.put(MediaStore.Video.Media.TITLE, "My video title")
    values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
    values.put(MediaStore.Video.Media.RELATIVE_PATH, path)
    
    requireActivity().contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values)
3

There are 3 best solutions below

5
blackapps On

Files in getExternalFilesDir() will not be scanned by the media store.

And hence will not be shown by Gallery apps.

0
Sumit Jangir On

Try this code and pass your saved file location here. This will work for Images and Video files. It'll work fine for videos but for images try 'Environment.DIRECTORY_DCIM' or 'Environment.DIRECTORY_PICTURES'

   fun Context.saveFileFromExternalStorageToScopedStorage(file: String): String {
    loge { "Downloaded File path: $file" }
    val lastPathSegment = file.toUri().lastPathSegment
        val sourceFile = File(file)
        var destinationDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
        if (!lastPathSegment.isNullOrEmpty()) {
            if (lastPathSegment.contains(".mp4")) {
            destinationDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
            }
        }

        loge { "destinationDir: $destinationDir SourceFile isExist: ${sourceFile.exists()}" }

        
    if (sourceFile.exists() && destinationDir != null) {
        val destinationFile =File(destinationDir, "$lastPathSegment")

        try {
            FileInputStream(sourceFile).use { inputStream ->
                FileOutputStream(destinationFile).use { outputStream ->
                    val buffer = ByteArray(4 * 1024)
                    var read: Int
                    while (inputStream.read(buffer).also { read = it } != -1) {
                        outputStream.write(buffer, 0, read)
                    }
                }
            }

            // Media file copied successfully
            MediaScanner(this, destinationFile).connect()
            return destinationFile.path
        } catch (e: Exception) {
            e.printStackTrace()
            return file
        }
    return file
   }

MediaScanner Class To scanFile

   class MediaScanner(val mContext: Context, val file: File) : MediaScannerConnectionClient {

    private var mediaScannerConnection: MediaScannerConnection =
        MediaScannerConnection(mContext, this)

    override fun onScanCompleted(path: String?, uri: Uri?) {
        loge { "onScanCompleted: Path: $path URI: $uri" }
        mediaScannerConnection.disconnect()
    }

    override fun onMediaScannerConnected() {
        mediaScannerConnection.scanFile(file.path, null)
    }

    fun connect() {
        loge { "Connect file to scan: $file" }
        mediaScannerConnection.connect()
    }
}
0
Sumit Jangir On

Here is another answer that will work fine for Media Files. This will show your downloaded files into the gallery.

// Function to read a media file as a string path and store it in Scoped Storage
fun saveMediaFileToScopedStorage(context: Context, mediaFilePath: String, mimeType: String): Uri? {
    val contentResolver: ContentResolver = context.contentResolver

    // Create a ContentValues object to store the file's metadata
    val contentValues = ContentValues().apply {
        put(MediaStore.MediaColumns.DISPLAY_NAME, File(mediaFilePath).name)
        put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
        put(
            MediaStore.MediaColumns.RELATIVE_PATH,
            if (mimeType.startsWith("image/")) Environment.DIRECTORY_PICTURES + File.separator + "yourDirectory/"
            else Environment.DIRECTORY_MOVIES + File.separator + "yourDirectory/"
        )
    }

    // Determine the appropriate MediaStore collection based on the file's MIME type
    val mediaCollection: Uri = when {
        mimeType.startsWith("image/") -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        mimeType.startsWith("video/") -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
        else -> throw IllegalArgumentException("Unsupported MIME type: $mimeType")
    }

    // Insert the content values into MediaStore to create a new file
    val uri = contentResolver.insert(mediaCollection, contentValues)

    uri?.let { mediaUri ->
        try {
            // Open an InputStream to read the media file
            val inputStream = FileInputStream(mediaFilePath)

            // Open an OutputStream to write the media file to the newly created MediaStore URI
            val outputStream = contentResolver.openOutputStream(mediaUri)

            inputStream.use { input ->
                outputStream?.use { output ->
                    input.copyTo(output)
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }

    return uri
}