diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/medialibraryscanning/MediaLibraryScanningClient.java b/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/medialibraryscanning/MediaLibraryScanningClient.java index 51b89751..f4485151 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/medialibraryscanning/MediaLibraryScanningClient.java +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/medialibraryscanning/MediaLibraryScanningClient.java @@ -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; diff --git a/app/src/tempo/java/com/cappielloantonio/tempo/service/MediaService.kt b/app/src/tempo/java/com/cappielloantonio/tempo/service/MediaService.kt index 058d932f..3791393f 100644 --- a/app/src/tempo/java/com/cappielloantonio/tempo/service/MediaService.kt +++ b/app/src/tempo/java/com/cappielloantonio/tempo/service/MediaService.kt @@ -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 - - private var customLayout = ImmutableList.of() - - 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 { - 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> { - 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> { - 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> { - 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>> { - 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 - ): ListenableFuture> { - 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) { - /* Do nothing. */ + clearListener() } private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false)