diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index 59b34c25ed..8ef87ce54f 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -59,6 +59,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; /** @@ -420,6 +421,45 @@ public final class MediaSessionConnector { * @return The {@link MediaMetadataCompat} to be published to the session. */ MediaMetadataCompat getMetadata(Player player); + + /** Returns whether the old and the new metadata are considered the same. */ + default boolean sameAs(MediaMetadataCompat oldMetadata, MediaMetadataCompat newMetadata) { + if (oldMetadata == newMetadata) { + return true; + } + if (oldMetadata.size() != newMetadata.size()) { + return false; + } + Set oldKeySet = oldMetadata.keySet(); + Bundle oldMetadataBundle = oldMetadata.getBundle(); + Bundle newMetadataBundle = newMetadata.getBundle(); + for (String key : oldKeySet) { + Object oldProperty = oldMetadataBundle.get(key); + Object newProperty = newMetadataBundle.get(key); + if (oldProperty == newProperty) { + continue; + } + if (oldProperty instanceof Bitmap && newProperty instanceof Bitmap) { + if (!((Bitmap) oldProperty).sameAs(((Bitmap) newProperty))) { + return false; + } + } else if (oldProperty instanceof RatingCompat && newProperty instanceof RatingCompat) { + RatingCompat oldRating = (RatingCompat) oldProperty; + RatingCompat newRating = (RatingCompat) newProperty; + if (oldRating.hasHeart() != newRating.hasHeart() + || oldRating.isRated() != newRating.isRated() + || oldRating.isThumbUp() != newRating.isThumbUp() + || oldRating.getPercentRating() != newRating.getPercentRating() + || oldRating.getStarRating() != newRating.getStarRating() + || oldRating.getRatingStyle() != newRating.getRatingStyle()) { + return false; + } + } else if (!Util.areEqual(oldProperty, newProperty)) { + return false; + } + } + return true; + } } /** The wrapped {@link MediaSessionCompat}. */ @@ -446,6 +486,7 @@ public final class MediaSessionConnector { @Nullable private MediaButtonEventHandler mediaButtonEventHandler; private long enabledPlaybackActions; + private boolean metadataDeduplicationEnabled; /** * Creates an instance. @@ -684,6 +725,19 @@ public final class MediaSessionConnector { } } + /** + * Sets whether {@link MediaMetadataProvider#sameAs(MediaMetadataCompat, MediaMetadataCompat)} + * should be consulted before calling {@link MediaSessionCompat#setMetadata(MediaMetadataCompat)}. + * + *

Note that this comparison is normally only required when you are using media sources that + * may introduce duplicate updates of the metadata for the same media item (e.g. live streams). + * + * @param metadataDeduplicationEnabled Whether to deduplicate metadata objects on invalidation. + */ + public void setMetadataDeduplicationEnabled(boolean metadataDeduplicationEnabled) { + this.metadataDeduplicationEnabled = metadataDeduplicationEnabled; + } + /** * Updates the metadata of the media session. * @@ -698,6 +752,14 @@ public final class MediaSessionConnector { mediaMetadataProvider != null && player != null ? mediaMetadataProvider.getMetadata(player) : METADATA_EMPTY; + @Nullable MediaMetadataProvider mediaMetadataProvider = this.mediaMetadataProvider; + if (metadataDeduplicationEnabled && mediaMetadataProvider != null) { + @Nullable MediaMetadataCompat oldMetadata = mediaSession.getController().getMetadata(); + if (oldMetadata != null && mediaMetadataProvider.sameAs(oldMetadata, metadata)) { + // Do not update if metadata did not change. + return; + } + } mediaSession.setMetadata(metadata); }