mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 17:43:32 +00:00
feat: cleaned up MediaService class, added support for Android Auto repository
This commit is contained in:
parent
1a407341ec
commit
ed60677608
1 changed files with 241 additions and 0 deletions
|
|
@ -0,0 +1,241 @@
|
|||
package com.cappielloantonio.tempo.service
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.session.CommandButton
|
||||
import androidx.media3.session.LibraryResult
|
||||
import androidx.media3.session.MediaLibraryService
|
||||
import androidx.media3.session.MediaSession
|
||||
import androidx.media3.session.SessionCommand
|
||||
import androidx.media3.session.SessionResult
|
||||
import com.cappielloantonio.tempo.R
|
||||
import com.cappielloantonio.tempo.repository.AutomotiveRepository
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
|
||||
open class MediaLibrarySessionCallback(
|
||||
context: Context,
|
||||
automotiveRepository: AutomotiveRepository
|
||||
) :
|
||||
MediaLibraryService.MediaLibrarySession.Callback {
|
||||
private val TAG = "MediaLibraryServiceCall"
|
||||
|
||||
init {
|
||||
MediaBrowserTree.initialize(context, automotiveRepository)
|
||||
}
|
||||
|
||||
private val customLayoutCommandButtons: List<CommandButton> = listOf(
|
||||
CommandButton.Builder()
|
||||
.setDisplayName(context.getString(R.string.exo_controls_shuffle_on_description))
|
||||
.setSessionCommand(
|
||||
SessionCommand(
|
||||
CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON, Bundle.EMPTY
|
||||
)
|
||||
).setIconResId(R.drawable.exo_icon_shuffle_off).build(),
|
||||
|
||||
CommandButton.Builder()
|
||||
.setDisplayName(context.getString(R.string.exo_controls_shuffle_off_description))
|
||||
.setSessionCommand(
|
||||
SessionCommand(
|
||||
CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF, Bundle.EMPTY
|
||||
)
|
||||
).setIconResId(R.drawable.exo_icon_shuffle_on).build()
|
||||
)
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
val mediaNotificationSessionCommands =
|
||||
MediaSession.ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon()
|
||||
.also { builder ->
|
||||
customLayoutCommandButtons.forEach { commandButton ->
|
||||
commandButton.sessionCommand?.let { builder.add(it) }
|
||||
}
|
||||
}.build()
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun onConnect(
|
||||
session: MediaSession, controller: MediaSession.ControllerInfo
|
||||
): MediaSession.ConnectionResult {
|
||||
if (session.isMediaNotificationController(controller) || session.isAutomotiveController(
|
||||
controller
|
||||
) || session.isAutoCompanionController(controller)
|
||||
) {
|
||||
val customLayout =
|
||||
customLayoutCommandButtons[if (session.player.shuffleModeEnabled) 1 else 0]
|
||||
|
||||
return MediaSession.ConnectionResult.AcceptedResultBuilder(session)
|
||||
.setAvailableSessionCommands(mediaNotificationSessionCommands)
|
||||
.setCustomLayout(ImmutableList.of(customLayout)).build()
|
||||
}
|
||||
|
||||
return MediaSession.ConnectionResult.AcceptedResultBuilder(session).build()
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun onCustomCommand(
|
||||
session: MediaSession,
|
||||
controller: MediaSession.ControllerInfo,
|
||||
customCommand: SessionCommand,
|
||||
args: Bundle
|
||||
): ListenableFuture<SessionResult> {
|
||||
if (CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON == customCommand.customAction) {
|
||||
session.player.shuffleModeEnabled = true
|
||||
session.setCustomLayout(
|
||||
session.mediaNotificationControllerInfo!!,
|
||||
ImmutableList.of(customLayoutCommandButtons[1])
|
||||
)
|
||||
|
||||
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
|
||||
} else if (CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF == customCommand.customAction) {
|
||||
session.player.shuffleModeEnabled = false
|
||||
session.setCustomLayout(
|
||||
session.mediaNotificationControllerInfo!!,
|
||||
ImmutableList.of(customLayoutCommandButtons[0])
|
||||
)
|
||||
|
||||
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
|
||||
}
|
||||
|
||||
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_ERROR_NOT_SUPPORTED))
|
||||
}
|
||||
|
||||
override fun onGetLibraryRoot(
|
||||
session: MediaLibraryService.MediaLibrarySession,
|
||||
browser: MediaSession.ControllerInfo,
|
||||
params: MediaLibraryService.LibraryParams?
|
||||
): ListenableFuture<LibraryResult<MediaItem>> {
|
||||
return Futures.immediateFuture(LibraryResult.ofItem(MediaBrowserTree.getRootItem(), params))
|
||||
}
|
||||
|
||||
override fun onGetChildren(
|
||||
session: MediaLibraryService.MediaLibrarySession,
|
||||
browser: MediaSession.ControllerInfo,
|
||||
parentId: String,
|
||||
page: Int,
|
||||
pageSize: Int,
|
||||
params: MediaLibraryService.LibraryParams?
|
||||
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
|
||||
return MediaBrowserTree.getChildren(parentId, params)
|
||||
}
|
||||
|
||||
/* override fun onGetItem(
|
||||
session: MediaLibraryService.MediaLibrarySession,
|
||||
browser: MediaSession.ControllerInfo,
|
||||
mediaId: String
|
||||
): ListenableFuture<LibraryResult<MediaItem>> {
|
||||
Log.d(TAG, "onGetItem()")
|
||||
|
||||
return MediaBrowserTree.getItem(mediaId)
|
||||
} */
|
||||
|
||||
/* override fun onAddMediaItems(
|
||||
mediaSession: MediaSession,
|
||||
controller: MediaSession.ControllerInfo,
|
||||
mediaItems: List<MediaItem>
|
||||
): ListenableFuture<List<MediaItem>> {
|
||||
Log.d(TAG, "onAddMediaItems()")
|
||||
|
||||
return Futures.immediateFuture(mediaItems)
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun onSetMediaItems(
|
||||
mediaSession: MediaSession,
|
||||
browser: MediaSession.ControllerInfo,
|
||||
mediaItems: List<MediaItem>,
|
||||
startIndex: Int,
|
||||
startPositionMs: Long
|
||||
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
|
||||
Log.d(TAG, "onSetMediaItems()")
|
||||
|
||||
val mediaItemss: MutableList<MediaItem> = ArrayList()
|
||||
|
||||
val mediaMetadata = MediaMetadata.Builder()
|
||||
.setTitle("Titolo")
|
||||
.setAlbumTitle("Titolo album")
|
||||
.setArtist("Artista")
|
||||
.setIsBrowsable(false)
|
||||
.setIsPlayable(true)
|
||||
.setMediaType(MediaMetadata.MEDIA_TYPE_MUSIC)
|
||||
.build()
|
||||
|
||||
val mediaItem = MediaItem.Builder()
|
||||
.setMediaId(mediaItems.get(0).mediaId)
|
||||
.setMediaMetadata(mediaMetadata)
|
||||
.setUri(MusicUtil.getStreamUri(mediaItems.get(0).mediaId))
|
||||
.build()
|
||||
|
||||
mediaItemss.add(mediaItem)
|
||||
|
||||
return Futures.immediateFuture(
|
||||
MediaSession.MediaItemsWithStartPosition(
|
||||
mediaItemss, 0, 0
|
||||
)
|
||||
)
|
||||
} */
|
||||
|
||||
/* @OptIn(UnstableApi::class) // MediaSession.MediaItemsWithStartPosition
|
||||
private fun maybeExpandSingleItemToPlaylist(
|
||||
mediaItem: MediaItem, startIndex: Int, startPositionMs: Long
|
||||
): MediaSession.MediaItemsWithStartPosition? {
|
||||
var playlist = listOf<MediaItem>()
|
||||
var indexInPlaylist = startIndex
|
||||
|
||||
MediaBrowserTree.getItem(mediaItem.mediaId)?.apply {
|
||||
if (mediaMetadata.isBrowsable == true) {
|
||||
playlist = MediaBrowserTree.getChildren(mediaId)
|
||||
} else if (requestMetadata.searchQuery == null) {
|
||||
MediaBrowserTree.getParentId(mediaId)?.let {
|
||||
playlist = MediaBrowserTree.getChildren(it).map { mediaItem ->
|
||||
if (mediaItem.mediaId == mediaId) MediaBrowserTree.expandItem(mediaItem)!! else mediaItem
|
||||
}
|
||||
|
||||
indexInPlaylist = MediaBrowserTree.getIndexInMediaItems(mediaId, playlist)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (playlist.isNotEmpty()) {
|
||||
return MediaSession.MediaItemsWithStartPosition(
|
||||
playlist, indexInPlaylist, startPositionMs
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
} */
|
||||
|
||||
/* override fun onSearch(
|
||||
session: MediaLibraryService.MediaLibrarySession,
|
||||
browser: MediaSession.ControllerInfo,
|
||||
query: String,
|
||||
params: MediaLibraryService.LibraryParams?
|
||||
): ListenableFuture<LibraryResult<Void>> {
|
||||
session.notifySearchResultChanged(browser, query, MediaBrowserTree.search(query).size, params)
|
||||
return Futures.immediateFuture(LibraryResult.ofVoid())
|
||||
} */
|
||||
|
||||
/* override fun onGetSearchResult(
|
||||
session: MediaLibraryService.MediaLibrarySession,
|
||||
browser: MediaSession.ControllerInfo,
|
||||
query: String,
|
||||
page: Int,
|
||||
pageSize: Int,
|
||||
params: MediaLibraryService.LibraryParams?
|
||||
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
|
||||
return Futures.immediateFuture(
|
||||
LibraryResult.ofItemList(
|
||||
MediaBrowserTree.search(query), params
|
||||
)
|
||||
)
|
||||
} */
|
||||
|
||||
companion object {
|
||||
private const val CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON =
|
||||
"android.media3.session.demo.SHUFFLE_ON"
|
||||
private const val CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF =
|
||||
"android.media3.session.demo.SHUFFLE_OFF"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue