Search code examples
androidkotlinmetadataandroid-permissionsandroid-external-storage

Loading MediaStore.Audio.Media.DATA not working for android 10 and above?


So I am making this app, in which I am fetching all audio files of the device.

private fun getAudioFiles() {
    
    val songs = mutableListOf<SongEntity>()
    val uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI

    // IS_MUSIC : Non-zero if the audio file is music
    val selection = MediaStore.Audio.Media.IS_MUSIC + "!= 0"

    // Sort the musics
    val sortOrder = MediaStore.Audio.Media.TITLE + " ASC"
    //val sortOrder = MediaStore.Audio.Media.TITLE + " DESC

    val contentResolver1 = ContextWrapper(applicationContext).contentResolver

    val cursor = contentResolver1!!.query(
        uri,
        null,
        selection,
        null,
        sortOrder
    )

    //looping through all rows and adding to list
    if (cursor != null && cursor.moveToFirst()) {
        do {
            val songName = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE))
            val artistName =
                cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST))
            val duration =
                cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION))
            val url = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))//.replace("\","\\\"")
            //val url = File(resolver.openFileDescriptor(uri, "r"))

            val songEntity =
                SongEntity(songs.size + 1, songName, artistName, parseLong(duration), url, -1)
            Log.i("FetchCheck", songEntity.toString())
            songs.add(songEntity)


            //insert song one by one
            //WORKING!!!
            //mAllSongsViewModel.insertSong(songEntity)


        } while (cursor.moveToNext())
    }
    //TODO - To send songs list to DB
    //TODO set shared preferences for isLoaded
    //fetch and initialize db with all songs at once
    //WORKING!!! TO INSERT MULTIPLE SONGS AT ONCE
    mAllSongsViewModel.insertSongs(songs)
    //finally set shared pref
    sharedPreferences.edit().putBoolean("songLoaded", true).apply()
}

Next I have to load all the details of song in any fragment which is fine. But I am unable to load cover photo for songs.

This is code of an adapter which needs to show recent tracks by their cover photos.

override fun onBindViewHolder(holder: RecentTrackViewHolder, position: Int) {
    if (songs != null) {
        val image=getAlbumCover(songs!![position].albumCover)
        if (image != null) {
            holder.imgSingleRecentTrack.setImageBitmap(BitmapFactory.decodeByteArray(image,0,image.size))
        }
        else{
            holder.imgSingleRecentTrack.setImageResource(R.drawable.drawable_cover)
        }
}

This is getAlbumCover method's code.

private fun getAlbumCover(url:String?): ByteArray?  {
    if(url==null)
        return null
    val mmr = MediaMetadataRetriever()

    try {
        mmr.setDataSource(url);
        Log.e("IMAGE","path OBTAINED for this song")
        return mmr.getEmbeddedPicture();
    }
    catch(e:Exception) {


        Log.e("IMAGE", e.message+e.stackTrace.toString()+"for path "+url)
        return null
    }

Now which I can ascertain is that all audio files are fetched properly and stored in database too. But when I try to load image from url of the audio file, I get this exception thrown. I have attached screenshots of respective log messages.

Logcat

According to log messages, I am assuming, it is setDataSource(url) which is throwing illegalArgumentException (as mentioned in it's documentation) here.

Now I don't know how to resolve this. I have tried this :

url.replace("\","\\\"")

Did not work. Please suggest me what should I do? Is there any other way? Or this error is solvable?

EDIT: Question title has been updated and question has been answered. Please refer to accepted answer.


Solution

  • Problem was use of deprecated method for fetching url. It will work fine upto android 9 right now.

    val url = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))
    

    To target higher version, use this:

    val albumArtColumn = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)
    val durationColumn = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION)
    val artistColumn = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)
    val titleColumn = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE)
    val idColumn = cursor.getColumnIndex(MediaStore.Audio.Media._ID)