From 3f408600cb79515bce45bbf0f63fca3fb73dfad2 Mon Sep 17 00:00:00 2001 From: Maxence G Date: Sat, 2 Jul 2022 21:47:32 +0200 Subject: [PATCH] Add const for custom SessionCommands Improve rating call --- .../ultrasonic/fragment/PlayerFragment.kt | 2 - .../playback/AutoMediaBrowserCallback.kt | 76 +++++++++++++------ .../playback/MediaNotificationProvider.kt | 2 +- .../service/MediaPlayerController.kt | 1 - 4 files changed, 53 insertions(+), 28 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt index f2aa408d..038e9b46 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt @@ -752,10 +752,8 @@ class PlayerFragment : if (currentSong == null) return true val isStarred = currentSong!!.starred - val id = currentSong!!.id mediaPlayerController.controller?.setRating( - id, HeartRating(!isStarred) )?.let { Futures.addCallback(it, object : FutureCallback { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/AutoMediaBrowserCallback.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/AutoMediaBrowserCallback.kt index 25625115..48c7b2b7 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/AutoMediaBrowserCallback.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/AutoMediaBrowserCallback.kt @@ -8,7 +8,11 @@ package org.moire.ultrasonic.playback import android.net.Uri +import android.os.Build import android.os.Bundle +import android.os.Looper +import android.widget.Toast +import android.widget.Toast.LENGTH_SHORT import androidx.media3.common.HeartRating import androidx.media3.common.MediaItem import androidx.media3.common.MediaMetadata @@ -29,13 +33,18 @@ import androidx.media3.session.SessionResult.RESULT_ERROR_BAD_VALUE import androidx.media3.session.SessionResult.RESULT_ERROR_UNKNOWN import androidx.media3.session.SessionResult.RESULT_SUCCESS import com.google.common.collect.ImmutableList +import com.google.common.util.concurrent.FutureCallback import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture +import com.google.common.util.concurrent.MoreExecutors import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.Runnable import kotlinx.coroutines.guava.future +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +import org.checkerframework.checker.units.qual.Length import org.koin.core.component.KoinComponent import org.koin.core.component.inject import org.moire.ultrasonic.R @@ -51,6 +60,7 @@ import org.moire.ultrasonic.service.MusicServiceFactory import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Util import timber.log.Timber +import kotlin.coroutines.coroutineContext private const val MEDIA_ROOT_ID = "MEDIA_ROOT_ID" private const val MEDIA_ALBUM_ID = "MEDIA_ALBUM_ID" @@ -87,6 +97,9 @@ private const val MEDIA_SEARCH_SONG_ITEM = "MEDIA_SEARCH_SONG_ITEM" private const val DISPLAY_LIMIT = 100 private const val SEARCH_LIMIT = 10 +// List of available custom SessionCommands +const val SESSION_CUSTOM_SET_RATING = "SESSION_CUSTOM_SET_RATING" + /** * MediaBrowserService implementation for e.g. Android Auto */ @@ -164,8 +177,7 @@ class AutoMediaBrowserCallback(var player: Player) : val connectionResult = super.onConnect(session, controller) val availableSessionCommands = connectionResult.availableSessionCommands.buildUpon() - // TODO: Make a Const value list of available custom SessionCommands - availableSessionCommands.add(SessionCommand("COMMAND_CODE_SESSION_SET_RATING", Bundle())) + availableSessionCommands.add(SessionCommand(SESSION_CUSTOM_SET_RATING, Bundle())) return MediaSession.ConnectionResult.accept( availableSessionCommands.build(), @@ -207,35 +219,52 @@ class AutoMediaBrowserCallback(var player: Player) : args: Bundle ): ListenableFuture { - /* - * It is currently not possible to edit a MediaItem after creation so the isRated value - * is stored in the track.starred value - */ - val rating = mediaPlayerController.currentPlayingLegacy?.track?.starred?.let { - HeartRating( - it - ) - } - if (rating is HeartRating) { - return when (customCommand.customAction) { - "COMMAND_CODE_SESSION_SET_RATING" -> { - onSetRating( + var customCommandFuture: ListenableFuture? = null + + when (customCommand.customAction) { + SESSION_CUSTOM_SET_RATING -> { + /* + * It is currently not possible to edit a MediaItem after creation so the isRated value + * is stored in the track.starred value + * See https://github.com/androidx/media/issues/33 + */ + val track = mediaPlayerController.currentPlayingLegacy?.track + if (track != null) { + customCommandFuture = onSetRating( session, controller, - HeartRating(!rating.isHeart) + HeartRating(!track.starred) ) - } - else -> { - Timber.d( - "CustomCommand not recognized %s with extra %s", - customCommand.customAction, - customCommand.customExtras.toString() + Futures.addCallback( + customCommandFuture, + object : FutureCallback { + override fun onSuccess(result: SessionResult) { + track.starred = !track.starred + // Handle notification reload here + } + + override fun onFailure(t: Throwable) { + Toast.makeText( + mediaPlayerController.context, + "There was an error updating the rating", + LENGTH_SHORT + ).show() + } + }, MoreExecutors.directExecutor() ) - super.onCustomCommand(session, controller, customCommand, args) } } + else -> { + Timber.d( + "CustomCommand not recognized %s with extra %s", + customCommand.customAction, + customCommand.customExtras.toString() + ) + } } + if (customCommandFuture != null) + return customCommandFuture return super.onCustomCommand(session, controller, customCommand, args) } @@ -274,7 +303,6 @@ class AutoMediaBrowserCallback(var player: Player) : // TODO: Better handle exception return@future SessionResult(RESULT_ERROR_UNKNOWN) } - mediaPlayerController.currentPlayingLegacy?.track?.starred = rating.isHeart return@future SessionResult(RESULT_SUCCESS) } return@future SessionResult(RESULT_ERROR_BAD_VALUE) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/MediaNotificationProvider.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/MediaNotificationProvider.kt index 15250879..4aab0519 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/MediaNotificationProvider.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/MediaNotificationProvider.kt @@ -51,7 +51,7 @@ class MediaNotificationProvider(context: Context) : .setIconResId(if (rating.isHeart) R.drawable.ic_star_full_dark else R.drawable.ic_star_hollow_dark) .setSessionCommand( SessionCommand( - "COMMAND_CODE_SESSION_SET_RATING", + SESSION_CUSTOM_SET_RATING, HeartRating(rating.isHeart).toBundle() ) ) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt index 0dc5939d..ffb5bfb2 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt @@ -594,7 +594,6 @@ class MediaPlayerController( } controller?.setRating( - song.id, HeartRating(!song.starred) ).let { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && it != null) {