diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/DumpableFormat.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/DumpableFormat.java index 5dfea7012c..bd638bee15 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/DumpableFormat.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/DumpableFormat.java @@ -15,15 +15,11 @@ */ package androidx.media3.test.utils; -import static androidx.media3.common.util.Assertions.checkNotNull; - import androidx.annotation.Nullable; import androidx.media3.common.ColorInfo; import androidx.media3.common.Format; -import androidx.media3.common.util.NullableType; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; -import com.google.common.base.Function; /** Wraps a {@link Format} to allow dumping it. */ @UnstableApi @@ -46,63 +42,54 @@ public final class DumpableFormat implements Dumper.Dumpable { @Override public void dump(Dumper dumper) { dumper.startBlock("format " + tag); - addIfNonDefault( - dumper, "averageBitrate", format, DEFAULT_FORMAT, format -> format.averageBitrate); - addIfNonDefault(dumper, "peakBitrate", format, DEFAULT_FORMAT, format -> format.peakBitrate); - addIfNonDefault(dumper, "id", format, DEFAULT_FORMAT, format -> format.id); - addIfNonDefault( - dumper, "containerMimeType", format, DEFAULT_FORMAT, format -> format.containerMimeType); - addIfNonDefault( - dumper, "sampleMimeType", format, DEFAULT_FORMAT, format -> format.sampleMimeType); - addIfNonDefault(dumper, "codecs", format, DEFAULT_FORMAT, format -> format.codecs); - addIfNonDefault(dumper, "maxInputSize", format, DEFAULT_FORMAT, format -> format.maxInputSize); - addIfNonDefault(dumper, "width", format, DEFAULT_FORMAT, format -> format.width); - addIfNonDefault(dumper, "height", format, DEFAULT_FORMAT, format -> format.height); - addIfNonDefault(dumper, "frameRate", format, DEFAULT_FORMAT, format -> format.frameRate); - addIfNonDefault( - dumper, "rotationDegrees", format, DEFAULT_FORMAT, format -> format.rotationDegrees); - addIfNonDefault( - dumper, - "pixelWidthHeightRatio", - format, - DEFAULT_FORMAT, - format -> format.pixelWidthHeightRatio); + dumper.addIfNonDefault( + "averageBitrate", format, DEFAULT_FORMAT, format -> format.averageBitrate); + dumper.addIfNonDefault("peakBitrate", format, DEFAULT_FORMAT, format -> format.peakBitrate); + dumper.addIfNonDefault("id", format, DEFAULT_FORMAT, format -> format.id); + dumper.addIfNonDefault( + "containerMimeType", format, DEFAULT_FORMAT, format -> format.containerMimeType); + dumper.addIfNonDefault( + "sampleMimeType", format, DEFAULT_FORMAT, format -> format.sampleMimeType); + dumper.addIfNonDefault("codecs", format, DEFAULT_FORMAT, format -> format.codecs); + dumper.addIfNonDefault("maxInputSize", format, DEFAULT_FORMAT, format -> format.maxInputSize); + dumper.addIfNonDefault("width", format, DEFAULT_FORMAT, format -> format.width); + dumper.addIfNonDefault("height", format, DEFAULT_FORMAT, format -> format.height); + dumper.addIfNonDefault("frameRate", format, DEFAULT_FORMAT, format -> format.frameRate); + dumper.addIfNonDefault( + "rotationDegrees", format, DEFAULT_FORMAT, format -> format.rotationDegrees); + dumper.addIfNonDefault( + "pixelWidthHeightRatio", format, DEFAULT_FORMAT, format -> format.pixelWidthHeightRatio); @Nullable ColorInfo colorInfo = format.colorInfo; if (colorInfo != null) { dumper.startBlock("colorInfo"); - addIfNonDefault(dumper, "colorSpace", colorInfo, DEFAULT_COLOR_INFO, c -> c.colorSpace); - addIfNonDefault(dumper, "colorRange", colorInfo, DEFAULT_COLOR_INFO, c -> c.colorRange); - addIfNonDefault(dumper, "colorTransfer", colorInfo, DEFAULT_COLOR_INFO, c -> c.colorTransfer); + dumper.addIfNonDefault("colorSpace", colorInfo, DEFAULT_COLOR_INFO, c -> c.colorSpace); + dumper.addIfNonDefault("colorRange", colorInfo, DEFAULT_COLOR_INFO, c -> c.colorRange); + dumper.addIfNonDefault("colorTransfer", colorInfo, DEFAULT_COLOR_INFO, c -> c.colorTransfer); if (colorInfo.hdrStaticInfo != null) { dumper.add("hdrStaticInfo", colorInfo.hdrStaticInfo); } - addIfNonDefault(dumper, "lumaBitdepth", colorInfo, DEFAULT_COLOR_INFO, c -> c.lumaBitdepth); - addIfNonDefault( - dumper, "chromaBitdepth", colorInfo, DEFAULT_COLOR_INFO, c -> c.chromaBitdepth); + dumper.addIfNonDefault("lumaBitdepth", colorInfo, DEFAULT_COLOR_INFO, c -> c.lumaBitdepth); + dumper.addIfNonDefault( + "chromaBitdepth", colorInfo, DEFAULT_COLOR_INFO, c -> c.chromaBitdepth); dumper.endBlock(); } - addIfNonDefault(dumper, "channelCount", format, DEFAULT_FORMAT, format -> format.channelCount); - addIfNonDefault(dumper, "sampleRate", format, DEFAULT_FORMAT, format -> format.sampleRate); - addIfNonDefault(dumper, "pcmEncoding", format, DEFAULT_FORMAT, format -> format.pcmEncoding); - addIfNonDefault(dumper, "encoderDelay", format, DEFAULT_FORMAT, format -> format.encoderDelay); - addIfNonDefault( - dumper, "encoderPadding", format, DEFAULT_FORMAT, format -> format.encoderPadding); - addIfNonDefault( - dumper, "subsampleOffsetUs", format, DEFAULT_FORMAT, format -> format.subsampleOffsetUs); - addIfNonDefault( - dumper, + dumper.addIfNonDefault("channelCount", format, DEFAULT_FORMAT, format -> format.channelCount); + dumper.addIfNonDefault("sampleRate", format, DEFAULT_FORMAT, format -> format.sampleRate); + dumper.addIfNonDefault("pcmEncoding", format, DEFAULT_FORMAT, format -> format.pcmEncoding); + dumper.addIfNonDefault("encoderDelay", format, DEFAULT_FORMAT, format -> format.encoderDelay); + dumper.addIfNonDefault( + "encoderPadding", format, DEFAULT_FORMAT, format -> format.encoderPadding); + dumper.addIfNonDefault( + "subsampleOffsetUs", format, DEFAULT_FORMAT, format -> format.subsampleOffsetUs); + dumper.addIfNonDefault( "selectionFlags", format, DEFAULT_FORMAT, format -> Util.getSelectionFlagStrings(format.selectionFlags)); - addIfNonDefault( - dumper, - "roleFlags", - format, - DEFAULT_FORMAT, - format -> Util.getRoleFlagStrings(format.roleFlags)); - addIfNonDefault(dumper, "language", format, DEFAULT_FORMAT, format -> format.language); - addIfNonDefault(dumper, "label", format, DEFAULT_FORMAT, format -> format.label); + dumper.addIfNonDefault( + "roleFlags", format, DEFAULT_FORMAT, format -> Util.getRoleFlagStrings(format.roleFlags)); + dumper.addIfNonDefault("language", format, DEFAULT_FORMAT, format -> format.language); + dumper.addIfNonDefault("label", format, DEFAULT_FORMAT, format -> format.label); if (!format.labels.isEmpty()) { dumper.startBlock("labels"); for (int i = 0; i < format.labels.size(); i++) { @@ -117,7 +104,7 @@ public final class DumpableFormat implements Dumper.Dumpable { if (format.drmInitData != null) { dumper.add("drmInitData", format.drmInitData.hashCode()); } - addIfNonDefault(dumper, "metadata", format, DEFAULT_FORMAT, format -> format.metadata); + dumper.addIfNonDefault("metadata", format, DEFAULT_FORMAT, format -> format.metadata); if (!format.initializationData.isEmpty()) { dumper.startBlock("initializationData"); for (int i = 0; i < format.initializationData.size(); i++) { @@ -146,18 +133,4 @@ public final class DumpableFormat implements Dumper.Dumpable { result = 31 * result + tag.hashCode(); return result; } - - private void addIfNonDefault( - Dumper dumper, - String field, - T value, - T defaultValue, - Function getFieldFunction) { - @Nullable Object fieldValue = getFieldFunction.apply(value); - @Nullable Object defaultFieldValue = getFieldFunction.apply(defaultValue); - if (!Util.areEqual(fieldValue, defaultFieldValue)) { - checkNotNull(fieldValue); - dumper.add(field, fieldValue); - } - } } diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/Dumper.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/Dumper.java index 4da377ebed..536eefab19 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/Dumper.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/Dumper.java @@ -15,9 +15,14 @@ */ package androidx.media3.test.utils; +import static androidx.media3.common.util.Assertions.checkNotNull; + +import androidx.annotation.Nullable; import androidx.media3.common.C; +import androidx.media3.common.util.NullableType; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; +import com.google.common.base.Function; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Arrays; import java.util.Locale; @@ -75,6 +80,40 @@ public final class Dumper { return addLine(string); } + /** + * Calls {@link #add(String, Object)} if {@code value} is not equal to {@code defaultValue}. + * + *

It is not permitted to pass a null value to {@link #add}, so null is only permitted here as + * a default value. Passing {@code value == null && defaultValue != null} will result in a {@link + * NullPointerException}. + */ + @CanIgnoreReturnValue + public Dumper addIfNonDefault( + String field, @Nullable Object value, @Nullable Object defaultValue) { + if (!Util.areEqual(value, defaultValue)) { + checkNotNull(value); + add(field, value); + } + return this; + } + + /** + * Applies {@code valueTransformFunction} to {@code value} and {@code defaultValue} and passes the + * results to {@link #addIfNonDefault(String, Object, Object)}. + * + *

See {@link #addIfNonDefault(String, Object, Object)} for limitations around when null + * results from {@code valueTransformFunction} are permitted. + */ + @CanIgnoreReturnValue + public Dumper addIfNonDefault( + String field, + T value, + T defaultValue, + Function valueTransformFunction) { + return addIfNonDefault( + field, valueTransformFunction.apply(value), valueTransformFunction.apply(defaultValue)); + } + @CanIgnoreReturnValue public Dumper addTime(String field, long time) { return add(field, time == C.TIME_UNSET ? "UNSET TIME" : time); diff --git a/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/PlaybackOutput.java b/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/PlaybackOutput.java index 12c49cb9eb..f174592d91 100644 --- a/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/PlaybackOutput.java +++ b/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/PlaybackOutput.java @@ -15,7 +15,6 @@ */ package androidx.media3.test.utils.robolectric; -import static androidx.media3.common.util.Assertions.checkNotNull; import static java.lang.Math.max; import android.graphics.Bitmap; @@ -33,7 +32,6 @@ import androidx.media3.common.ThumbRating; import androidx.media3.common.text.Cue; import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.UnstableApi; -import androidx.media3.common.util.Util; import androidx.media3.container.MdtaMetadataEntry; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.extractor.metadata.dvbsi.AppInfoTable; @@ -182,39 +180,39 @@ public final class PlaybackOutput implements Dumper.Dumpable { for (int i = 0; i < mediaMetadatas.size(); i++) { dumper.startBlock("MediaMetadata[" + i + "]"); MediaMetadata mediaMetadata = mediaMetadatas.get(i); - dumpIfNotEqual(dumper, "title", mediaMetadata.title, null); - dumpIfNotEqual(dumper, "artist", mediaMetadata.artist, null); - dumpIfNotEqual(dumper, "albumTitle", mediaMetadata.albumTitle, null); - dumpIfNotEqual(dumper, "albumArtist", mediaMetadata.albumArtist, null); - dumpIfNotEqual(dumper, "displayTitle", mediaMetadata.displayTitle, null); - dumpIfNotEqual(dumper, "subtitle", mediaMetadata.subtitle, null); - dumpIfNotEqual(dumper, "description", mediaMetadata.description, null); - dumpIfNotEqual(dumper, "userRating", ratingString(mediaMetadata.userRating), null); - dumpIfNotEqual(dumper, "overallRating", ratingString(mediaMetadata.overallRating), null); - dumpIfNotEqual(dumper, "artworkData", mediaMetadata.artworkData, null); - dumpIfNotEqual( - dumper, "artworkDataType", pictureTypeString(mediaMetadata.artworkDataType), null); - dumpIfNotEqual(dumper, "artworkUri", mediaMetadata.artworkUri, null); - dumpIfNotEqual(dumper, "trackNumber", mediaMetadata.trackNumber, null); - dumpIfNotEqual(dumper, "totalTrackCount", mediaMetadata.totalTrackCount, null); - dumpIfNotEqual(dumper, "isBrowsable", mediaMetadata.isBrowsable, null); - dumpIfNotEqual(dumper, "isPlayable", mediaMetadata.isPlayable, null); - dumpIfNotEqual(dumper, "recordingYear", mediaMetadata.recordingYear, null); - dumpIfNotEqual(dumper, "recordingMonth", mediaMetadata.recordingMonth, null); - dumpIfNotEqual(dumper, "recordingDay", mediaMetadata.recordingDay, null); - dumpIfNotEqual(dumper, "releaseYear", mediaMetadata.releaseYear, null); - dumpIfNotEqual(dumper, "releaseMonth", mediaMetadata.releaseMonth, null); - dumpIfNotEqual(dumper, "releaseDay", mediaMetadata.releaseDay, null); - dumpIfNotEqual(dumper, "writer", mediaMetadata.writer, null); - dumpIfNotEqual(dumper, "composer", mediaMetadata.composer, null); - dumpIfNotEqual(dumper, "conductor", mediaMetadata.conductor, null); - dumpIfNotEqual(dumper, "discNumber", mediaMetadata.discNumber, null); - dumpIfNotEqual(dumper, "totalDiscCount", mediaMetadata.totalDiscCount, null); - dumpIfNotEqual(dumper, "genre", mediaMetadata.genre, null); - dumpIfNotEqual(dumper, "compilation", mediaMetadata.compilation, null); - dumpIfNotEqual(dumper, "station", mediaMetadata.station, null); - dumpIfNotEqual(dumper, "mediaType", mediaTypeString(mediaMetadata.mediaType), null); - dumpIfNotEqual(dumper, "extras", mediaMetadata.extras, null); + dumper.addIfNonDefault("title", mediaMetadata.title, null); + dumper.addIfNonDefault("artist", mediaMetadata.artist, null); + dumper.addIfNonDefault("albumTitle", mediaMetadata.albumTitle, null); + dumper.addIfNonDefault("albumArtist", mediaMetadata.albumArtist, null); + dumper.addIfNonDefault("displayTitle", mediaMetadata.displayTitle, null); + dumper.addIfNonDefault("subtitle", mediaMetadata.subtitle, null); + dumper.addIfNonDefault("description", mediaMetadata.description, null); + dumper.addIfNonDefault("userRating", ratingString(mediaMetadata.userRating), null); + dumper.addIfNonDefault("overallRating", ratingString(mediaMetadata.overallRating), null); + dumper.addIfNonDefault("artworkData", mediaMetadata.artworkData, null); + dumper.addIfNonDefault( + "artworkDataType", pictureTypeString(mediaMetadata.artworkDataType), null); + dumper.addIfNonDefault("artworkUri", mediaMetadata.artworkUri, null); + dumper.addIfNonDefault("trackNumber", mediaMetadata.trackNumber, null); + dumper.addIfNonDefault("totalTrackCount", mediaMetadata.totalTrackCount, null); + dumper.addIfNonDefault("isBrowsable", mediaMetadata.isBrowsable, null); + dumper.addIfNonDefault("isPlayable", mediaMetadata.isPlayable, null); + dumper.addIfNonDefault("recordingYear", mediaMetadata.recordingYear, null); + dumper.addIfNonDefault("recordingMonth", mediaMetadata.recordingMonth, null); + dumper.addIfNonDefault("recordingDay", mediaMetadata.recordingDay, null); + dumper.addIfNonDefault("releaseYear", mediaMetadata.releaseYear, null); + dumper.addIfNonDefault("releaseMonth", mediaMetadata.releaseMonth, null); + dumper.addIfNonDefault("releaseDay", mediaMetadata.releaseDay, null); + dumper.addIfNonDefault("writer", mediaMetadata.writer, null); + dumper.addIfNonDefault("composer", mediaMetadata.composer, null); + dumper.addIfNonDefault("conductor", mediaMetadata.conductor, null); + dumper.addIfNonDefault("discNumber", mediaMetadata.discNumber, null); + dumper.addIfNonDefault("totalDiscCount", mediaMetadata.totalDiscCount, null); + dumper.addIfNonDefault("genre", mediaMetadata.genre, null); + dumper.addIfNonDefault("compilation", mediaMetadata.compilation, null); + dumper.addIfNonDefault("station", mediaMetadata.station, null); + dumper.addIfNonDefault("mediaType", mediaTypeString(mediaMetadata.mediaType), null); + dumper.addIfNonDefault("extras", mediaMetadata.extras, null); dumper.endBlock(); } dumper.endBlock(); @@ -401,22 +399,22 @@ public final class PlaybackOutput implements Dumper.Dumpable { for (int j = 0; j < subtitle.size(); j++) { dumper.startBlock("Cue[" + j + "]"); Cue cue = subtitle.get(j); - dumpIfNotEqual(dumper, "text", cue.text, null); - dumpIfNotEqual(dumper, "textAlignment", cue.textAlignment, null); + dumper.addIfNonDefault("text", cue.text, null); + dumper.addIfNonDefault("textAlignment", cue.textAlignment, null); dumpBitmap(dumper, cue.bitmap); - dumpIfNotEqual(dumper, "line", cue.line, Cue.DIMEN_UNSET); - dumpIfNotEqual(dumper, "lineType", cue.lineType, Cue.TYPE_UNSET); - dumpIfNotEqual(dumper, "lineAnchor", cue.lineAnchor, Cue.TYPE_UNSET); - dumpIfNotEqual(dumper, "position", cue.position, Cue.DIMEN_UNSET); - dumpIfNotEqual(dumper, "positionAnchor", cue.positionAnchor, Cue.TYPE_UNSET); - dumpIfNotEqual(dumper, "size", cue.size, Cue.DIMEN_UNSET); - dumpIfNotEqual(dumper, "bitmapHeight", cue.bitmapHeight, Cue.DIMEN_UNSET); + dumper.addIfNonDefault("line", cue.line, Cue.DIMEN_UNSET); + dumper.addIfNonDefault("lineType", cue.lineType, Cue.TYPE_UNSET); + dumper.addIfNonDefault("lineAnchor", cue.lineAnchor, Cue.TYPE_UNSET); + dumper.addIfNonDefault("position", cue.position, Cue.DIMEN_UNSET); + dumper.addIfNonDefault("positionAnchor", cue.positionAnchor, Cue.TYPE_UNSET); + dumper.addIfNonDefault("size", cue.size, Cue.DIMEN_UNSET); + dumper.addIfNonDefault("bitmapHeight", cue.bitmapHeight, Cue.DIMEN_UNSET); if (cue.windowColorSet) { dumper.add("cue.windowColor", cue.windowColor); } - dumpIfNotEqual(dumper, "textSizeType", cue.textSizeType, Cue.TYPE_UNSET); - dumpIfNotEqual(dumper, "textSize", cue.textSize, Cue.DIMEN_UNSET); - dumpIfNotEqual(dumper, "verticalType", cue.verticalType, Cue.TYPE_UNSET); + dumper.addIfNonDefault("textSizeType", cue.textSizeType, Cue.TYPE_UNSET); + dumper.addIfNonDefault("textSize", cue.textSize, Cue.DIMEN_UNSET); + dumper.addIfNonDefault("verticalType", cue.verticalType, Cue.TYPE_UNSET); dumper.endBlock(); } dumper.endBlock(); @@ -424,14 +422,6 @@ public final class PlaybackOutput implements Dumper.Dumpable { dumper.endBlock(); } - private static void dumpIfNotEqual( - Dumper dumper, String field, @Nullable Object actual, @Nullable Object comparison) { - if (!Util.areEqual(actual, comparison)) { - checkNotNull(actual); - dumper.add(field, actual); - } - } - private static void dumpBitmap(Dumper dumper, @Nullable Bitmap bitmap) { if (bitmap == null) { return;