Modernize code after media3 1.1.0 update

This commit is contained in:
birdbird 2023-07-24 21:08:01 +00:00
parent acbaae9f14
commit 0492b0fa6f
5 changed files with 62 additions and 74 deletions

View File

@ -11,7 +11,7 @@ import android.annotation.SuppressLint
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import androidx.media3.session.BitmapLoader import androidx.media3.common.util.BitmapLoader
import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.ListeningExecutorService import com.google.common.util.concurrent.ListeningExecutorService
import com.google.common.util.concurrent.MoreExecutors import com.google.common.util.concurrent.MoreExecutors

View File

@ -7,16 +7,15 @@
package org.moire.ultrasonic.playback package org.moire.ultrasonic.playback
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import androidx.media3.common.HeartRating import androidx.media3.common.HeartRating
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata import androidx.media3.common.MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_ALBUMS import androidx.media3.common.MediaMetadata.MEDIA_TYPE_FOLDER_ARTISTS
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_ARTISTS import androidx.media3.common.MediaMetadata.MEDIA_TYPE_FOLDER_MIXED
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_MIXED import androidx.media3.common.MediaMetadata.MEDIA_TYPE_FOLDER_PLAYLISTS
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_PLAYLISTS import androidx.media3.common.MediaMetadata.MEDIA_TYPE_MIXED
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_TITLES import androidx.media3.common.MediaMetadata.MEDIA_TYPE_PLAYLIST
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.common.Rating import androidx.media3.common.Rating
import androidx.media3.common.StarRating import androidx.media3.common.StarRating
@ -46,7 +45,6 @@ import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.SearchCriteria import org.moire.ultrasonic.domain.SearchCriteria
import org.moire.ultrasonic.domain.SearchResult import org.moire.ultrasonic.domain.SearchResult
import org.moire.ultrasonic.domain.Track import org.moire.ultrasonic.domain.Track
import org.moire.ultrasonic.service.MediaPlayerManager
import org.moire.ultrasonic.service.MusicServiceFactory import org.moire.ultrasonic.service.MusicServiceFactory
import org.moire.ultrasonic.service.RatingManager import org.moire.ultrasonic.service.RatingManager
import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.util.Util
@ -97,11 +95,8 @@ const val PLAY_COMMAND = "play "
* MediaBrowserService implementation for e.g. Android Auto * MediaBrowserService implementation for e.g. Android Auto
*/ */
@Suppress("TooManyFunctions", "LargeClass", "UnusedPrivateMember") @Suppress("TooManyFunctions", "LargeClass", "UnusedPrivateMember")
@SuppressLint("UnsafeOptInUsageError") class AutoMediaBrowserCallback : MediaLibraryService.MediaLibrarySession.Callback, KoinComponent {
class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
MediaLibraryService.MediaLibrarySession.Callback, KoinComponent {
private val mediaPlayerManager by inject<MediaPlayerManager>()
private val activeServerProvider: ActiveServerProvider by inject() private val activeServerProvider: ActiveServerProvider by inject()
private val serviceJob = SupervisorJob() private val serviceJob = SupervisorJob()
@ -213,8 +208,8 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
"Root Folder", "Root Folder",
MEDIA_ROOT_ID, MEDIA_ROOT_ID,
isPlayable = false, isPlayable = false,
folderType = FOLDER_TYPE_MIXED, isBrowsable = true,
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED mediaType = MEDIA_TYPE_FOLDER_MIXED
), ),
params params
) )
@ -528,7 +523,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
?: Futures.immediateFuture(mediaItems) ?: Futures.immediateFuture(mediaItems)
} }
@Suppress("ComplexMethod") @Suppress("ReturnCount", "ComplexMethod")
private fun onLoadChildren( private fun onLoadChildren(
parentId: String, parentId: String,
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> { ): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
@ -598,8 +593,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
mediaItems.add( mediaItems.add(
album.title ?: "", album.title ?: "",
listOf(MEDIA_ALBUM_ITEM, album.id, album.name) listOf(MEDIA_ALBUM_ITEM, album.id, album.name)
.joinToString("|"), .joinToString("|")
FOLDER_TYPE_ALBUMS
) )
} }
@ -691,7 +685,8 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
R.string.music_library_label, R.string.music_library_label,
MEDIA_LIBRARY_ID, MEDIA_LIBRARY_ID,
null, null,
folderType = FOLDER_TYPE_MIXED, isBrowsable = true,
mediaType = MEDIA_TYPE_FOLDER_MIXED,
icon = R.drawable.ic_library icon = R.drawable.ic_library
) )
@ -699,7 +694,8 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
R.string.main_artists_title, R.string.main_artists_title,
MEDIA_ARTIST_ID, MEDIA_ARTIST_ID,
null, null,
folderType = FOLDER_TYPE_ARTISTS, isBrowsable = true,
mediaType = MEDIA_TYPE_FOLDER_ARTISTS,
icon = R.drawable.ic_artist icon = R.drawable.ic_artist
) )
@ -708,7 +704,8 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
R.string.main_albums_title, R.string.main_albums_title,
MEDIA_ALBUM_ID, MEDIA_ALBUM_ID,
null, null,
folderType = FOLDER_TYPE_ALBUMS, isBrowsable = true,
mediaType = MEDIA_TYPE_FOLDER_ALBUMS,
icon = R.drawable.ic_menu_browse icon = R.drawable.ic_menu_browse
) )
@ -716,7 +713,8 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
R.string.playlist_label, R.string.playlist_label,
MEDIA_PLAYLIST_ID, MEDIA_PLAYLIST_ID,
null, null,
folderType = FOLDER_TYPE_PLAYLISTS, isBrowsable = true,
mediaType = MEDIA_TYPE_FOLDER_PLAYLISTS,
icon = R.drawable.ic_menu_playlists icon = R.drawable.ic_menu_playlists
) )
@ -731,14 +729,16 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
R.string.main_songs_random, R.string.main_songs_random,
MEDIA_SONG_RANDOM_ID, MEDIA_SONG_RANDOM_ID,
R.string.main_songs_title, R.string.main_songs_title,
folderType = FOLDER_TYPE_TITLES isBrowsable = true,
mediaType = MEDIA_TYPE_PLAYLIST
) )
mediaItems.add( mediaItems.add(
R.string.main_songs_starred, R.string.main_songs_starred,
MEDIA_SONG_STARRED_ID, MEDIA_SONG_STARRED_ID,
R.string.main_songs_title, R.string.main_songs_title,
folderType = FOLDER_TYPE_TITLES isBrowsable = true,
mediaType = MEDIA_TYPE_PLAYLIST
) )
// Albums // Albums
@ -752,28 +752,28 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
R.string.main_albums_recent, R.string.main_albums_recent,
MEDIA_ALBUM_RECENT_ID, MEDIA_ALBUM_RECENT_ID,
R.string.main_albums_title, R.string.main_albums_title,
folderType = FOLDER_TYPE_ALBUMS mediaType = MEDIA_TYPE_FOLDER_ALBUMS,
) )
mediaItems.add( mediaItems.add(
R.string.main_albums_frequent, R.string.main_albums_frequent,
MEDIA_ALBUM_FREQUENT_ID, MEDIA_ALBUM_FREQUENT_ID,
R.string.main_albums_title, R.string.main_albums_title,
folderType = FOLDER_TYPE_ALBUMS mediaType = MEDIA_TYPE_FOLDER_ALBUMS,
) )
mediaItems.add( mediaItems.add(
R.string.main_albums_random, R.string.main_albums_random,
MEDIA_ALBUM_RANDOM_ID, MEDIA_ALBUM_RANDOM_ID,
R.string.main_albums_title, R.string.main_albums_title,
folderType = FOLDER_TYPE_ALBUMS mediaType = MEDIA_TYPE_FOLDER_ALBUMS,
) )
mediaItems.add( mediaItems.add(
R.string.main_albums_starred, R.string.main_albums_starred,
MEDIA_ALBUM_STARRED_ID, MEDIA_ALBUM_STARRED_ID,
R.string.main_albums_title, R.string.main_albums_title,
folderType = FOLDER_TYPE_ALBUMS mediaType = MEDIA_TYPE_FOLDER_ALBUMS,
) )
// Other // Other
@ -822,8 +822,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
index.add(currentSection) index.add(currentSection)
mediaItems.add( mediaItems.add(
currentSection, currentSection,
listOf(MEDIA_ARTIST_SECTION, currentSection).joinToString("|"), listOf(MEDIA_ARTIST_SECTION, currentSection).joinToString("|")
FOLDER_TYPE_ARTISTS
) )
} }
} }
@ -831,8 +830,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
artists.map { artist -> artists.map { artist ->
mediaItems.add( mediaItems.add(
artist.name ?: "", artist.name ?: "",
listOf(childMediaId, artist.id, artist.name).joinToString("|"), listOf(childMediaId, artist.id, artist.name).joinToString("|")
FOLDER_TYPE_ARTISTS
) )
} }
} }
@ -862,8 +860,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
mediaItems.add( mediaItems.add(
album.title ?: "", album.title ?: "",
listOf(MEDIA_ALBUM_ITEM, album.id, album.name) listOf(MEDIA_ALBUM_ITEM, album.id, album.name)
.joinToString("|"), .joinToString("|")
FOLDER_TYPE_ALBUMS
) )
} }
return@future LibraryResult.ofItemList(mediaItems, null) return@future LibraryResult.ofItemList(mediaItems, null)
@ -901,8 +898,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
if (item.isDirectory) if (item.isDirectory)
mediaItems.add( mediaItems.add(
item.title ?: "", item.title ?: "",
listOf(MEDIA_ALBUM_ITEM, item.id, item.name).joinToString("|"), listOf(MEDIA_ALBUM_ITEM, item.id, item.name).joinToString("|")
FOLDER_TYPE_TITLES
) )
else if (item is Track) else if (item is Track)
mediaItems.add( mediaItems.add(
@ -951,8 +947,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
mediaItems.add( mediaItems.add(
album.title ?: "", album.title ?: "",
listOf(MEDIA_ALBUM_ITEM, album.id, album.name) listOf(MEDIA_ALBUM_ITEM, album.id, album.name)
.joinToString("|"), .joinToString("|")
FOLDER_TYPE_ALBUMS
) )
} }
@ -980,7 +975,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
playlist.name, playlist.name,
listOf(MEDIA_PLAYLIST_ITEM, playlist.id, playlist.name) listOf(MEDIA_PLAYLIST_ITEM, playlist.id, playlist.name)
.joinToString("|"), .joinToString("|"),
FOLDER_TYPE_PLAYLISTS mediaType = MEDIA_TYPE_PLAYLIST,
) )
} }
return@future LibraryResult.ofItemList(mediaItems, null) return@future LibraryResult.ofItemList(mediaItems, null)
@ -1074,7 +1069,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
mediaItems.add( mediaItems.add(
podcast.title ?: "", podcast.title ?: "",
listOf(MEDIA_PODCAST_ITEM, podcast.id).joinToString("|"), listOf(MEDIA_PODCAST_ITEM, podcast.id).joinToString("|"),
FOLDER_TYPE_MIXED mediaType = MEDIA_TYPE_FOLDER_MIXED,
) )
} }
return@future LibraryResult.ofItemList(mediaItems, null) return@future LibraryResult.ofItemList(mediaItems, null)
@ -1177,7 +1172,7 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
share.name ?: "", share.name ?: "",
listOf(MEDIA_SHARE_ITEM, share.id) listOf(MEDIA_SHARE_ITEM, share.id)
.joinToString("|"), .joinToString("|"),
FOLDER_TYPE_MIXED mediaType = MEDIA_TYPE_FOLDER_MIXED,
) )
} }
return@future LibraryResult.ofItemList(mediaItems, null) return@future LibraryResult.ofItemList(mediaItems, null)
@ -1355,14 +1350,16 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
private fun MutableList<MediaItem>.add( private fun MutableList<MediaItem>.add(
title: String, title: String,
mediaId: String, mediaId: String,
folderType: Int mediaType: Int = MEDIA_TYPE_MIXED,
isBrowsable: Boolean = false
) { ) {
val mediaItem = buildMediaItem( val mediaItem = buildMediaItem(
title, title,
mediaId, mediaId,
isPlayable = false, isPlayable = false,
folderType = folderType isBrowsable = isBrowsable,
mediaType = mediaType
) )
this.add(mediaItem) this.add(mediaItem)
@ -1373,8 +1370,8 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
resId: Int, resId: Int,
mediaId: String, mediaId: String,
groupNameId: Int?, groupNameId: Int?,
browsable: Boolean = true, isBrowsable: Boolean = true,
folderType: Int = FOLDER_TYPE_MIXED, mediaType: Int = MEDIA_TYPE_FOLDER_MIXED,
icon: Int? = null icon: Int? = null
) { ) {
val applicationContext = UApp.applicationContext() val applicationContext = UApp.applicationContext()
@ -1382,14 +1379,15 @@ class AutoMediaBrowserCallback(val libraryService: MediaLibraryService) :
val mediaItem = buildMediaItem( val mediaItem = buildMediaItem(
applicationContext.getString(resId), applicationContext.getString(resId),
mediaId, mediaId,
isPlayable = !browsable, isPlayable = !isBrowsable,
folderType = folderType, isBrowsable = isBrowsable,
imageUri = if (icon != null) {
Util.getUriToDrawable(applicationContext, icon)
} else null,
group = if (groupNameId != null) { group = if (groupNameId != null) {
applicationContext.getString(groupNameId) applicationContext.getString(groupNameId)
} else null, } else null,
imageUri = if (icon != null) { mediaType = mediaType
Util.getUriToDrawable(applicationContext, icon)
} else null
) )
this.add(mediaItem) this.add(mediaItem)

View File

@ -142,7 +142,7 @@ class PlaybackService :
actualBackend = desiredBackend actualBackend = desiredBackend
// Create browser interface // Create browser interface
librarySessionCallback = AutoMediaBrowserCallback(this) librarySessionCallback = AutoMediaBrowserCallback()
// This will need to use the AutoCalls // This will need to use the AutoCalls
mediaLibrarySession = MediaLibrarySession.Builder(this, player, librarySessionCallback) mediaLibrarySession = MediaLibrarySession.Builder(this, player, librarySessionCallback)

View File

@ -82,7 +82,10 @@ class JukeboxMediaPlayer : JukeboxUnimplementedFunctions(), Player {
companion object { companion object {
// This is quite important, by setting the DeviceInfo the player is recognized by // This is quite important, by setting the DeviceInfo the player is recognized by
// Android as being a remote playback surface // Android as being a remote playback surface
val DEVICE_INFO = DeviceInfo(DeviceInfo.PLAYBACK_TYPE_REMOTE, 0, 10) val DEVICE_INFO = DeviceInfo.Builder(DeviceInfo.PLAYBACK_TYPE_REMOTE)
.setMinVolume(0)
.setMaxVolume(10)
.build()
val running = AtomicBoolean() val running = AtomicBoolean()
const val MAX_GAIN = 10 const val MAX_GAIN = 10
} }
@ -208,15 +211,12 @@ class JukeboxMediaPlayer : JukeboxUnimplementedFunctions(), Player {
Player.COMMAND_GET_DEVICE_VOLUME, Player.COMMAND_GET_DEVICE_VOLUME,
Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS,
Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS, Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS,
Player.COMMAND_ADJUST_DEVICE_VOLUME,
Player.COMMAND_SET_DEVICE_VOLUME
) )
if (isPlaying) commandsBuilder.add(Player.COMMAND_STOP) if (isPlaying) commandsBuilder.add(Player.COMMAND_STOP)
if (playlist.isNotEmpty()) { if (playlist.isNotEmpty()) {
commandsBuilder.addAll( commandsBuilder.addAll(
Player.COMMAND_GET_CURRENT_MEDIA_ITEM, Player.COMMAND_GET_CURRENT_MEDIA_ITEM,
Player.COMMAND_GET_METADATA, Player.COMMAND_GET_METADATA,
Player.COMMAND_GET_MEDIA_ITEMS_METADATA,
Player.COMMAND_PLAY_PAUSE, Player.COMMAND_PLAY_PAUSE,
Player.COMMAND_PREPARE, Player.COMMAND_PREPARE,
Player.COMMAND_SEEK_BACK, Player.COMMAND_SEEK_BACK,

View File

@ -14,7 +14,8 @@ import androidx.core.net.toUri
import androidx.media3.common.HeartRating import androidx.media3.common.HeartRating
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata import androidx.media3.common.MediaMetadata
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_NONE import androidx.media3.common.MediaMetadata.MEDIA_TYPE_FOLDER_MIXED
import androidx.media3.common.MediaMetadata.MEDIA_TYPE_MUSIC
import androidx.media3.common.StarRating import androidx.media3.common.StarRating
import java.text.DateFormat import java.text.DateFormat
import java.text.ParseException import java.text.ParseException
@ -22,7 +23,7 @@ import java.util.Date
import org.moire.ultrasonic.domain.Track import org.moire.ultrasonic.domain.Track
import org.moire.ultrasonic.provider.AlbumArtContentProvider import org.moire.ultrasonic.provider.AlbumArtContentProvider
// Copied from androidx.media.utils.MediaConstants in order to avoid importing a whole dependecy // Copied from androidx.media.utils.MediaConstants in order to avoid importing a whole dependency
// for a single string value // for a single string value
private const val DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE = private const val DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE =
"android.media.browse.CONTENT_STYLE_GROUP_TITLE_HINT" "android.media.browse.CONTENT_STYLE_GROUP_TITLE_HINT"
@ -76,15 +77,16 @@ fun Track.toMediaItem(
title = title ?: "", title = title ?: "",
mediaId = mediaId, mediaId = mediaId,
isPlayable = !isDirectory, isPlayable = !isDirectory,
folderType = if (isDirectory) MediaMetadata.FOLDER_TYPE_TITLES isBrowsable = isDirectory,
else MediaMetadata.FOLDER_TYPE_NONE,
album = album, album = album,
artist = artist, artist = artist,
genre = genre, genre = genre,
sourceUri = uri.toUri(), sourceUri = uri.toUri(),
imageUri = artworkUri, imageUri = artworkUri,
starred = starred, starred = starred,
group = null group = null,
mediaType = if (isDirectory) MEDIA_TYPE_FOLDER_MIXED
else MEDIA_TYPE_MUSIC
) )
val metadataBuilder = mediaItem.mediaMetadata.buildUpon() val metadataBuilder = mediaItem.mediaMetadata.buildUpon()
@ -204,14 +206,6 @@ private fun safeParseDate(created: String?): Date? {
} else null } else null
} }
fun MediaItem.setPin(pin: Boolean) {
this.mediaMetadata.extras?.putBoolean("pin", pin)
}
fun MediaItem.shouldBePinned(): Boolean {
return this.mediaMetadata.extras?.getBoolean("pin") ?: false
}
/** /**
* Build a new MediaItem from a list of attributes. * Build a new MediaItem from a list of attributes.
* Especially useful to create folder entries in the Auto interface. * Especially useful to create folder entries in the Auto interface.
@ -222,7 +216,7 @@ fun buildMediaItem(
title: String, title: String,
mediaId: String, mediaId: String,
isPlayable: Boolean, isPlayable: Boolean,
folderType: @MediaMetadata.FolderType Int, isBrowsable: Boolean = false,
album: String? = null, album: String? = null,
artist: String? = null, artist: String? = null,
genre: String? = null, genre: String? = null,
@ -241,17 +235,13 @@ fun buildMediaItem(
.setAlbumArtist(artist) .setAlbumArtist(artist)
.setGenre(genre) .setGenre(genre)
.setUserRating(HeartRating(starred)) .setUserRating(HeartRating(starred))
.setFolderType(folderType) .setIsBrowsable(isBrowsable)
.setIsPlayable(isPlayable) .setIsPlayable(isPlayable)
if (imageUri != null) { if (imageUri != null) {
metadataBuilder.setArtworkUri(imageUri) metadataBuilder.setArtworkUri(imageUri)
} }
if (folderType > FOLDER_TYPE_NONE) {
metadataBuilder.setIsBrowsable(true)
}
if (mediaType != null) { if (mediaType != null) {
metadataBuilder.setMediaType(mediaType) metadataBuilder.setMediaType(mediaType)
} }