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