androidandroid-contentprovidermediastoreandroid-music-playerandroid-10.0

How to update metadata of audio file in Android Q media store?


Updating metadata of audio file in media store is not working in Android Q OS, it works in all other OS.

I am using content provider with uri specified as MediaStore.Audio.Media.EXTERNAL_CONTENT_URI. It is working fine in all below Android Q device. Below is the code that I am using to update track metadata.

ContentValues cv = new ContentValues();
ContentResolver resolver = getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;

cv.put(MediaStore.Audio.Media.TITLE, newTitle);
cv.put(MediaStore.Audio.Media.ALBUM, newAlbumName);
cv.put(MediaStore.Audio.Media.ARTIST, newArtistName);

int rowsUpdated = resolver.update(uri, cv, 
MediaStore.Audio.Media._ID + " = ? ", new String[]{audioId});

For Android Q device, rowsUpdated is always 0 with no exception. How are other music player updating tracks metadata in Android Q ?


Solution

  • Finally, it took some time but I figured that out.

    First, you need to obtain access to file. Here you can read about that

    Next, I found out that to update title or artist fields (maybe others to, I didn't test them) you need to set column MediaStore.Audio.Media.IS_PENDING value to 1. Like that:

        val id = //Your audio file id
    
        val values = ContentValues()
        values.put(MediaStore.Audio.Media.IS_PENDING, 1)
    
        val uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id)
        contentResolver.update(uri, values, null, null)
    

    And then you can edit fields that you need. Also to end the update process set MediaStore.Audio.Media.IS_PENDING to 0 again:

        val id = //Your audio file id
        val title = //New title
        val artist = //New artist
    
        val values = ContentValues()
        values.put(MediaStore.Audio.Media.IS_PENDING, 0)
        values.put(MediaStore.Audio.Media.TITLE, title)
        values.put(MediaStore.Audio.Media.ARTIST, artist)
    
        val uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id)
        contentResolver.update(uri, values, null, null)
    

    So in one function, it would look like this:

        @RequiresApi(value = android.os.Build.VERSION_CODES.Q)
        fun updateMetadata(contentResolver: ContentResolver, id: Long, title: String, artist: String) {
            val uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id)
            val values = ContentValues()
            
            values.put(MediaStore.Audio.Media.IS_PENDING, 1)
            contentResolver.update(uri, values, null, null)
            
            values.clear()
            values.put(MediaStore.Audio.Media.IS_PENDING, 0)
            values.put(MediaStore.Audio.Media.TITLE, title)
            values.put(MediaStore.Audio.Media.ARTIST, artist)
            contentResolver.update(uri, values, null, null)
        }
    

    It's written in Kotlin but I think you will figure out how to do that in java.

    UPDATE

    By updating MediaStore you don't updating real file at any android version. That means, if a file would be updated (for example: renamed) and/or scanned by MediaScannerConnection your changes will be lost. This answer is right.