Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class MediaService : MediaLibraryService() {

private lateinit var player: ExoPlayer
private lateinit var mediaLibrarySession: MediaLibrarySession
private lateinit var customCommands: List<CommandButton>
private lateinit var shuffleCommands: List<CommandButton>
private lateinit var repeatCommands: List<CommandButton>

private var customLayout = ImmutableList.of<CommandButton>()

Expand All @@ -41,6 +42,12 @@ class MediaService : MediaLibraryService() {
"android.media3.session.demo.SHUFFLE_ON"
private const val CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF =
"android.media3.session.demo.SHUFFLE_OFF"
private const val CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_OFF =
"android.media3.session.demo.REPEAT_OFF"
private const val CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ONE =
"android.media3.session.demo.REPEAT_ONE"
private const val CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL =
"android.media3.session.demo.REPEAT_ALL"
}

override fun onCreate() {
Expand Down Expand Up @@ -72,7 +79,7 @@ class MediaService : MediaLibraryService() {
val connectionResult = super.onConnect(session, controller)
val availableSessionCommands = connectionResult.availableSessionCommands.buildUpon()

customCommands.forEach { commandButton ->
shuffleCommands.forEach { commandButton ->
// TODO: Aggiungere i comandi personalizzati
// commandButton.sessionCommand?.let { availableSessionCommands.add(it) }
}
Expand All @@ -89,22 +96,40 @@ class MediaService : MediaLibraryService() {
}
}

fun buildCustomLayout(player: Player): ImmutableList<CommandButton> {
val shuffle = shuffleCommands[if (player.shuffleModeEnabled) 1 else 0]
val repeat = when (player.repeatMode) {
Player.REPEAT_MODE_ONE -> repeatCommands[1]
Player.REPEAT_MODE_ALL -> repeatCommands[2]
else -> repeatCommands[0]
}
return ImmutableList.of(shuffle, repeat)
}

override fun onCustomCommand(
session: MediaSession,
controller: ControllerInfo,
customCommand: SessionCommand,
args: Bundle
): ListenableFuture<SessionResult> {
if (CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON == customCommand.customAction) {
player.shuffleModeEnabled = true
customLayout = ImmutableList.of(customCommands[1])
session.setCustomLayout(customLayout)
} else if (CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF == customCommand.customAction) {
player.shuffleModeEnabled = false
customLayout = ImmutableList.of(customCommands[0])
session.setCustomLayout(customLayout)
when (customCommand.customAction) {
CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON -> player.shuffleModeEnabled = true
CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF -> player.shuffleModeEnabled = false
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_OFF,
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL,
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ONE -> {
val nextMode = when (player.repeatMode) {
Player.REPEAT_MODE_ONE -> Player.REPEAT_MODE_ALL
Player.REPEAT_MODE_OFF -> Player.REPEAT_MODE_ONE
else -> Player.REPEAT_MODE_OFF
}
player.repeatMode = nextMode
}
}

customLayout = librarySessionCallback.buildCustomLayout(player)
session.setCustomLayout(customLayout)

return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
}

Expand All @@ -125,17 +150,28 @@ class MediaService : MediaLibraryService() {
}

private fun initializeCustomCommands() {
customCommands =
listOf(
getShuffleCommandButton(
SessionCommand(CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON, Bundle.EMPTY)
),
getShuffleCommandButton(
SessionCommand(CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF, Bundle.EMPTY)
)
shuffleCommands = listOf(
getShuffleCommandButton(
SessionCommand(CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON, Bundle.EMPTY)
),
getShuffleCommandButton(
SessionCommand(CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF, Bundle.EMPTY)
)
)

repeatCommands = listOf(
getRepeatCommandButton(
SessionCommand(CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_OFF, Bundle.EMPTY)
),
getRepeatCommandButton(
SessionCommand(CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ONE, Bundle.EMPTY)
),
getRepeatCommandButton(
SessionCommand(CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL, Bundle.EMPTY)
)
)

customLayout = ImmutableList.of(customCommands[0])
customLayout = ImmutableList.of(shuffleCommands[0], repeatCommands[0])
}

private fun initializePlayer() {
Expand All @@ -147,6 +183,9 @@ class MediaService : MediaLibraryService() {
.setWakeMode(C.WAKE_MODE_NETWORK)
.setLoadControl(initializeLoadControl())
.build()

player.shuffleModeEnabled = Preferences.isShuffleModeEnabled()
player.repeatMode = Preferences.getRepeatMode()
}

private fun initializeMediaLibrarySession() {
Expand Down Expand Up @@ -224,6 +263,18 @@ class MediaService : MediaLibraryService() {
}
}
}

override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
Preferences.setShuffleModeEnabled(shuffleModeEnabled)
customLayout = librarySessionCallback.buildCustomLayout(player)
mediaLibrarySession.setCustomLayout(customLayout)
}

override fun onRepeatModeChanged(repeatMode: Int) {
Preferences.setRepeatMode(repeatMode)
customLayout = librarySessionCallback.buildCustomLayout(player)
mediaLibrarySession.setCustomLayout(customLayout)
}
})
}

Expand Down Expand Up @@ -251,6 +302,25 @@ class MediaService : MediaLibraryService() {
.build()
}

@SuppressLint("PrivateResource")
private fun getRepeatCommandButton(sessionCommand: SessionCommand): CommandButton {
val icon = when (sessionCommand.customAction) {
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ONE -> R.drawable.exo_icon_repeat_one
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL -> R.drawable.exo_icon_repeat_all
else -> R.drawable.exo_icon_repeat_off
}
val description = when (sessionCommand.customAction) {
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ONE -> R.string.exo_controls_repeat_one_description
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL -> R.string.exo_controls_repeat_all_description
else -> R.string.exo_controls_repeat_off_description
}
return CommandButton.Builder()
.setDisplayName(getString(description))
.setSessionCommand(sessionCommand)
.setIconResId(icon)
.build()
}

private fun ignoreFuture(customLayout: ListenableFuture<SessionResult>) {
/* Do nothing. */
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import android.os.Bundle
import androidx.annotation.OptIn
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.session.CommandButton
import androidx.media3.session.LibraryResult
Expand All @@ -27,7 +28,7 @@ open class MediaLibrarySessionCallback(
MediaBrowserTree.initialize(automotiveRepository)
}

private val customLayoutCommandButtons: List<CommandButton> = listOf(
private val shuffleCommandButtons: List<CommandButton> = listOf(
CommandButton.Builder()
.setDisplayName(context.getString(R.string.exo_controls_shuffle_on_description))
.setSessionCommand(
Expand All @@ -45,15 +46,46 @@ open class MediaLibrarySessionCallback(
).setIconResId(R.drawable.exo_icon_shuffle_on).build()
)

private val repeatCommandButtons: List<CommandButton> = listOf(
CommandButton.Builder()
.setDisplayName(context.getString(R.string.exo_controls_repeat_off_description))
.setSessionCommand(SessionCommand(CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_OFF, Bundle.EMPTY))
.setIconResId(R.drawable.exo_icon_repeat_off)
.build(),
CommandButton.Builder()
.setDisplayName(context.getString(R.string.exo_controls_repeat_one_description))
.setSessionCommand(SessionCommand(CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ONE, Bundle.EMPTY))
.setIconResId(R.drawable.exo_icon_repeat_one)
.build(),
CommandButton.Builder()
.setDisplayName(context.getString(R.string.exo_controls_repeat_all_description))
.setSessionCommand(SessionCommand(CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL, Bundle.EMPTY))
.setIconResId(R.drawable.exo_icon_repeat_all)
.build()
)

private val customLayoutCommandButtons: List<CommandButton> =
shuffleCommandButtons + repeatCommandButtons

@OptIn(UnstableApi::class)
val mediaNotificationSessionCommands =
MediaSession.ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon()
.also { builder ->
customLayoutCommandButtons.forEach { commandButton ->
(shuffleCommandButtons + repeatCommandButtons).forEach { commandButton ->
commandButton.sessionCommand?.let { builder.add(it) }
}
}.build()

fun buildCustomLayout(player: Player): ImmutableList<CommandButton> {
val shuffle = shuffleCommandButtons[if (player.shuffleModeEnabled) 1 else 0]
val repeat = when (player.repeatMode) {
Player.REPEAT_MODE_ONE -> repeatCommandButtons[1]
Player.REPEAT_MODE_ALL -> repeatCommandButtons[2]
else -> repeatCommandButtons[0]
}
return ImmutableList.of(shuffle, repeat)
}

@OptIn(UnstableApi::class)
override fun onConnect(
session: MediaSession, controller: MediaSession.ControllerInfo
Expand All @@ -62,12 +94,11 @@ open class MediaLibrarySessionCallback(
controller
) || session.isAutoCompanionController(controller)
) {
val customLayout =
customLayoutCommandButtons[if (session.player.shuffleModeEnabled) 1 else 0]
val customLayout = buildCustomLayout(session.player)

return MediaSession.ConnectionResult.AcceptedResultBuilder(session)
.setAvailableSessionCommands(mediaNotificationSessionCommands)
.setCustomLayout(ImmutableList.of(customLayout)).build()
.setCustomLayout(customLayout).build()
}

return MediaSession.ConnectionResult.AcceptedResultBuilder(session).build()
Expand All @@ -80,25 +111,28 @@ open class MediaLibrarySessionCallback(
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))
when (customCommand.customAction) {
CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON -> session.player.shuffleModeEnabled = true
CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF -> session.player.shuffleModeEnabled = false
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_OFF,
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL,
CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ONE -> {
val nextMode = when (session.player.repeatMode) {
Player.REPEAT_MODE_ONE -> Player.REPEAT_MODE_ALL
Player.REPEAT_MODE_OFF -> Player.REPEAT_MODE_ONE
else -> Player.REPEAT_MODE_OFF
}
session.player.repeatMode = nextMode
}
else -> return Futures.immediateFuture(SessionResult(SessionResult.RESULT_ERROR_NOT_SUPPORTED))
}

return Futures.immediateFuture(SessionResult(SessionResult.RESULT_ERROR_NOT_SUPPORTED))
session.setCustomLayout(
session.mediaNotificationControllerInfo!!,
buildCustomLayout(session.player)
)

return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
}

override fun onGetLibraryRoot(
Expand Down Expand Up @@ -158,5 +192,11 @@ open class MediaLibrarySessionCallback(
"android.media3.session.demo.SHUFFLE_ON"
private const val CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_OFF =
"android.media3.session.demo.SHUFFLE_OFF"
private const val CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_OFF =
"android.media3.session.demo.REPEAT_OFF"
private const val CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ONE =
"android.media3.session.demo.REPEAT_ONE"
private const val CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL =
"android.media3.session.demo.REPEAT_ALL"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
private lateinit var player: ExoPlayer
private lateinit var castPlayer: CastPlayer
private lateinit var mediaLibrarySession: MediaLibrarySession
private lateinit var librarySessionCallback: MediaLibrarySessionCallback

override fun onCreate() {
super.onCreate()
Expand Down Expand Up @@ -79,6 +80,9 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
.setWakeMode(C.WAKE_MODE_NETWORK)
.setLoadControl(initializeLoadControl())
.build()

player.shuffleModeEnabled = Preferences.isShuffleModeEnabled()
player.repeatMode = Preferences.getRepeatMode()
}

private fun initializeCastPlayer() {
Expand All @@ -97,13 +101,14 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
getPendingIntent(0, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)
}

librarySessionCallback = createLibrarySessionCallback()
mediaLibrarySession =
MediaLibrarySession.Builder(this, player, createLibrarySessionCallback())
MediaLibrarySession.Builder(this, player, librarySessionCallback)
.setSessionActivity(sessionActivityPendingIntent)
.build()
}

private fun createLibrarySessionCallback(): MediaLibrarySession.Callback {
private fun createLibrarySessionCallback(): MediaLibrarySessionCallback {
return MediaLibrarySessionCallback(this, automotiveRepository)
}

Expand Down Expand Up @@ -166,6 +171,20 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
}
}
}

override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
Preferences.setShuffleModeEnabled(shuffleModeEnabled)
mediaLibrarySession.setCustomLayout(
librarySessionCallback.buildCustomLayout(player)
)
}

override fun onRepeatModeChanged(repeatMode: Int) {
Preferences.setRepeatMode(repeatMode)
mediaLibrarySession.setCustomLayout(
librarySessionCallback.buildCustomLayout(player)
)
}
})
}

Expand Down
Loading