mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 09:33:33 +00:00
feat: cleaned up MediaService class, added support for Android Auto repository
This commit is contained in:
parent
567350771c
commit
1a407341ec
2 changed files with 25 additions and 174 deletions
|
|
@ -9,7 +9,7 @@ import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
|||
import retrofit2.Call;
|
||||
|
||||
public class MediaLibraryScanningClient {
|
||||
private static final String TAG = "SystemClient";
|
||||
private static final String TAG = "MediaLibraryScanningClient";
|
||||
|
||||
private final Subsonic subsonic;
|
||||
private final MediaLibraryScanningService mediaLibraryScanningService;
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
package com.cappielloantonio.tempo.service
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent.FLAG_IMMUTABLE
|
||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||
import android.app.TaskStackBuilder
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.media3.cast.CastPlayer
|
||||
import androidx.media3.cast.SessionAvailabilityListener
|
||||
import androidx.media3.common.*
|
||||
import androidx.media3.common.AudioAttributes
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.Tracks
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.DefaultLoadControl
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.session.*
|
||||
import androidx.media3.session.MediaLibraryService
|
||||
import androidx.media3.session.MediaSession.ControllerInfo
|
||||
import com.cappielloantonio.tempo.R
|
||||
import com.cappielloantonio.tempo.repository.AutomotiveRepository
|
||||
import com.cappielloantonio.tempo.ui.activity.MainActivity
|
||||
import com.cappielloantonio.tempo.util.Constants
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil
|
||||
|
|
@ -24,33 +26,19 @@ import com.cappielloantonio.tempo.util.ReplayGainUtil
|
|||
import com.google.android.gms.cast.framework.CastContext
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GoogleApiAvailability
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
|
||||
|
||||
@UnstableApi
|
||||
class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||
private val librarySessionCallback = CustomMediaLibrarySessionCallback()
|
||||
|
||||
private lateinit var automotiveRepository: AutomotiveRepository
|
||||
private lateinit var player: ExoPlayer
|
||||
private lateinit var castPlayer: CastPlayer
|
||||
private lateinit var mediaLibrarySession: MediaLibrarySession
|
||||
private lateinit var customCommands: List<CommandButton>
|
||||
|
||||
private var customLayout = ImmutableList.of<CommandButton>()
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
initializeCustomCommands()
|
||||
initializeRepository()
|
||||
initializePlayer()
|
||||
initializeCastPlayer()
|
||||
initializeMediaLibrarySession()
|
||||
|
|
@ -66,140 +54,21 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
|||
return mediaLibrarySession
|
||||
}
|
||||
|
||||
override fun onTaskRemoved(rootIntent: Intent?) {
|
||||
val player = mediaLibrarySession.player
|
||||
|
||||
if (!player.playWhenReady || player.mediaItemCount == 0) {
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
releasePlayer()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private inner class CustomMediaLibrarySessionCallback : MediaLibrarySession.Callback {
|
||||
|
||||
override fun onConnect(
|
||||
session: MediaSession,
|
||||
controller: ControllerInfo
|
||||
): MediaSession.ConnectionResult {
|
||||
val connectionResult = super.onConnect(session, controller)
|
||||
val availableSessionCommands = connectionResult.availableSessionCommands.buildUpon()
|
||||
|
||||
customCommands.forEach { commandButton ->
|
||||
// TODO: Aggiungere i comandi personalizzati
|
||||
// commandButton.sessionCommand?.let { availableSessionCommands.add(it) }
|
||||
}
|
||||
|
||||
return MediaSession.ConnectionResult.accept(
|
||||
availableSessionCommands.build(),
|
||||
connectionResult.availablePlayerCommands
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPostConnect(session: MediaSession, controller: ControllerInfo) {
|
||||
if (!customLayout.isEmpty() && controller.controllerVersion != 0) {
|
||||
ignoreFuture(mediaLibrarySession.setCustomLayout(controller, customLayout))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
|
||||
}
|
||||
|
||||
/* override fun onGetLibraryRoot(
|
||||
session: MediaLibrarySession,
|
||||
browser: ControllerInfo,
|
||||
params: LibraryParams?
|
||||
): ListenableFuture<LibraryResult<MediaItem>> {
|
||||
if (params != null && params.isRecent) {
|
||||
return Futures.immediateFuture(LibraryResult.ofError(LibraryResult.RESULT_ERROR_NOT_SUPPORTED))
|
||||
}
|
||||
return Futures.immediateFuture(LibraryResult.ofItem(MediaItemTree.getRootItem(), params))
|
||||
}
|
||||
|
||||
override fun onGetItem(
|
||||
session: MediaLibrarySession,
|
||||
browser: ControllerInfo,
|
||||
mediaId: String
|
||||
): ListenableFuture<LibraryResult<MediaItem>> {
|
||||
val item =
|
||||
MediaItemTree.getItem(mediaId)
|
||||
?: return Futures.immediateFuture(
|
||||
LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE)
|
||||
)
|
||||
return Futures.immediateFuture(LibraryResult.ofItem(item, /* params= */ null))
|
||||
}
|
||||
|
||||
override fun onSubscribe(
|
||||
session: MediaLibrarySession,
|
||||
browser: ControllerInfo,
|
||||
parentId: String,
|
||||
params: LibraryParams?
|
||||
): ListenableFuture<LibraryResult<Void>> {
|
||||
val children =
|
||||
MediaItemTree.getChildren(parentId)
|
||||
?: return Futures.immediateFuture(
|
||||
LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE)
|
||||
)
|
||||
session.notifyChildrenChanged(browser, parentId, children.size, params)
|
||||
return Futures.immediateFuture(LibraryResult.ofVoid())
|
||||
}
|
||||
|
||||
override fun onGetChildren(
|
||||
session: MediaLibrarySession,
|
||||
browser: ControllerInfo,
|
||||
parentId: String,
|
||||
page: Int,
|
||||
pageSize: Int,
|
||||
params: LibraryParams?
|
||||
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
|
||||
val children =
|
||||
MediaItemTree.getChildren(parentId)
|
||||
?: return Futures.immediateFuture(
|
||||
LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE)
|
||||
)
|
||||
|
||||
return Futures.immediateFuture(LibraryResult.ofItemList(children, params))
|
||||
}*/
|
||||
|
||||
override fun onAddMediaItems(
|
||||
mediaSession: MediaSession,
|
||||
controller: ControllerInfo,
|
||||
mediaItems: List<MediaItem>
|
||||
): ListenableFuture<List<MediaItem>> {
|
||||
val updatedMediaItems = mediaItems.map {
|
||||
it.buildUpon()
|
||||
.setUri(it.requestMetadata.mediaUri)
|
||||
.setMediaMetadata(it.mediaMetadata)
|
||||
.setMimeType(MimeTypes.BASE_TYPE_AUDIO)
|
||||
.build()
|
||||
}
|
||||
return Futures.immediateFuture(updatedMediaItems)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
)
|
||||
|
||||
customLayout = ImmutableList.of(customCommands[0])
|
||||
private fun initializeRepository() {
|
||||
automotiveRepository = AutomotiveRepository()
|
||||
}
|
||||
|
||||
private fun initializePlayer() {
|
||||
|
|
@ -230,13 +99,13 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
|||
}
|
||||
|
||||
mediaLibrarySession =
|
||||
MediaLibrarySession.Builder(this, player, librarySessionCallback)
|
||||
MediaLibrarySession.Builder(this, player, createLibrarySessionCallback())
|
||||
.setSessionActivity(sessionActivityPendingIntent)
|
||||
.build()
|
||||
}
|
||||
|
||||
if (!customLayout.isEmpty()) {
|
||||
mediaLibrarySession.setCustomLayout(customLayout)
|
||||
}
|
||||
private fun createLibrarySessionCallback(): MediaLibrarySession.Callback {
|
||||
return MediaLibrarySessionCallback(this, automotiveRepository)
|
||||
}
|
||||
|
||||
private fun initializePlayerListener() {
|
||||
|
|
@ -316,25 +185,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
|||
if (this::castPlayer.isInitialized) castPlayer.release()
|
||||
player.release()
|
||||
mediaLibrarySession.release()
|
||||
}
|
||||
|
||||
@SuppressLint("PrivateResource")
|
||||
private fun getShuffleCommandButton(sessionCommand: SessionCommand): CommandButton {
|
||||
val isOn = sessionCommand.customAction == CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON
|
||||
return CommandButton.Builder()
|
||||
.setDisplayName(
|
||||
getString(
|
||||
if (isOn) R.string.exo_controls_shuffle_on_description
|
||||
else R.string.exo_controls_shuffle_off_description
|
||||
)
|
||||
)
|
||||
.setSessionCommand(sessionCommand)
|
||||
.setIconResId(if (isOn) R.drawable.exo_icon_shuffle_off else R.drawable.exo_icon_shuffle_on)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun ignoreFuture(customLayout: ListenableFuture<SessionResult>) {
|
||||
/* Do nothing. */
|
||||
clearListener()
|
||||
}
|
||||
|
||||
private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue