From e79809616cd0ecb6f39cbeffdaaf143c260f64e6 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 9 Nov 2023 09:58:17 -0800 Subject: [PATCH] Don't crash when receiving a bad playback state PiperOrigin-RevId: 580942377 --- .../media3/session/LegacyConversions.java | 24 +++++++++++++++--- .../session/MediaControllerImplLegacy.java | 25 ++++++++++++++----- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/libraries/session/src/main/java/androidx/media3/session/LegacyConversions.java b/libraries/session/src/main/java/androidx/media3/session/LegacyConversions.java index e7646445ed3..aa9901c967e 100644 --- a/libraries/session/src/main/java/androidx/media3/session/LegacyConversions.java +++ b/libraries/session/src/main/java/androidx/media3/session/LegacyConversions.java @@ -143,6 +143,17 @@ MediaMetadataCompat.METADATA_KEY_DOWNLOAD_STATUS, MediaConstants.EXTRAS_KEY_MEDIA_TYPE_COMPAT); + /** Exception thrown when the conversion between legacy and Media3 states fails. */ + public static class ConversionException extends Exception { + private ConversionException(String message) { + super(message); + } + + private ConversionException(String message, Throwable cause) { + super(message, cause); + } + } + /** Converts {@link PlaybackStateCompat} to {@link PlaybackException}. */ @Nullable public static PlaybackException convertToPlaybackException( @@ -810,11 +821,16 @@ public static boolean convertToPlayWhenReady(@Nullable PlaybackStateCompat playb return false; } - /** Converts a {@link PlaybackStateCompat} to {@link Player.State} */ + /** + * Converts a {@link PlaybackStateCompat} to {@link Player.State} + * + * @throws ConversionException if the legacy state of the remote session is invalid + */ public static @Player.State int convertToPlaybackState( @Nullable PlaybackStateCompat playbackStateCompat, @Nullable MediaMetadataCompat currentMediaMetadata, - long timeDiffMs) { + long timeDiffMs) + throws ConversionException { if (playbackStateCompat == null) { return Player.STATE_IDLE; } @@ -842,8 +858,8 @@ public static boolean convertToPlayWhenReady(@Nullable PlaybackStateCompat playb convertToCurrentPositionMs(playbackStateCompat, currentMediaMetadata, timeDiffMs); return (currentPosition < duration) ? Player.STATE_READY : Player.STATE_ENDED; default: - throw new IllegalStateException( - "Unrecognized PlaybackStateCompat: " + playbackStateCompat.getState()); + throw new ConversionException( + "Invalid state of PlaybackStateCompat: " + playbackStateCompat.getState()); } } diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java index f0c82038188..cb76b99c122 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java @@ -22,6 +22,7 @@ import static androidx.media3.session.MediaUtils.calculateBufferedPercentage; import static java.lang.Math.max; import static java.lang.Math.min; +import static java.lang.String.format; import android.app.PendingIntent; import android.content.Context; @@ -73,6 +74,7 @@ import androidx.media3.common.util.NullableType; import androidx.media3.common.util.Size; import androidx.media3.common.util.Util; +import androidx.media3.session.LegacyConversions.ConversionException; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -1491,6 +1493,7 @@ private void handleNewLegacyParameters( legacyPlayerInfo, controllerInfo, newLegacyPlayerInfo, + controllerCompat.getPackageName(), controllerCompat.getFlags(), controllerCompat.isSessionReady(), controllerCompat.getRatingType(), @@ -1877,6 +1880,7 @@ private static ControllerInfo buildNewControllerInfo( LegacyPlayerInfo oldLegacyPlayerInfo, ControllerInfo oldControllerInfo, LegacyPlayerInfo newLegacyPlayerInfo, + String sessionPackageName, long sessionFlags, boolean isSessionReady, @RatingCompat.Style int ratingType, @@ -2027,12 +2031,21 @@ private static ControllerInfo buildNewControllerInfo( LegacyConversions.convertToAudioAttributes(newLegacyPlayerInfo.playbackInfoCompat); boolean playWhenReady = LegacyConversions.convertToPlayWhenReady(newLegacyPlayerInfo.playbackStateCompat); - @Player.State - int playbackState = - LegacyConversions.convertToPlaybackState( - newLegacyPlayerInfo.playbackStateCompat, - newLegacyPlayerInfo.mediaMetadataCompat, - timeDiffMs); + @Player.State int playbackState; + try { + playbackState = + LegacyConversions.convertToPlaybackState( + newLegacyPlayerInfo.playbackStateCompat, + newLegacyPlayerInfo.mediaMetadataCompat, + timeDiffMs); + } catch (ConversionException e) { + Log.e( + TAG, + format( + "Received invalid playback state %s from package %s. Keeping the previous state.", + newLegacyPlayerInfo.playbackStateCompat.getState(), sessionPackageName)); + playbackState = oldControllerInfo.playerInfo.playbackState; + } boolean isPlaying = LegacyConversions.convertToIsPlaying(newLegacyPlayerInfo.playbackStateCompat); DeviceInfo deviceInfo =