Add artwork display mode to PlayerView
This change deprecates `PlayerView.setUseArtwork(boolean)` and introduces `setArtworkDisplayMode(mode)` and `artworkDisplayMode="off|fit|fill"` instead. - off: no artwork is displayed (like deprecated useArtwork=false) - fit: letterbox like media (like deprecated useArtwork=true) - fill: scales the artwork to fill the entire width/weight of the player view #minor-release PiperOrigin-RevId: 534167226
This commit is contained in:
parent
96a4ae7e40
commit
46fb454b3f
@ -39,6 +39,8 @@
|
||||
example, a Bluetooth headset
|
||||
([#167](https://github.com/androidx/media/issues/167)).
|
||||
* UI:
|
||||
* Deprecate `PlayerView.setUseArtwork(boolean)` and replace it with
|
||||
`PlayerView.setArtworkDisplayMode(@ArtworkDisplayMode)`.
|
||||
* Downloads:
|
||||
* OkHttp Extension:
|
||||
* Cronet Extension:
|
||||
|
@ -501,6 +501,94 @@
|
||||
"totalTrackCount": 2,
|
||||
"duration": 160,
|
||||
"site": "https://www.youtube.com/audiolibrary/music"
|
||||
},
|
||||
{
|
||||
"id": "mixed_media_01",
|
||||
"title": "Tear of steal - DASH",
|
||||
"album": "Mixed media",
|
||||
"artist": "Mixed artists",
|
||||
"genre": "Mixed",
|
||||
"source": "https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd",
|
||||
"image": "https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd"
|
||||
},
|
||||
{
|
||||
"id": "mixed_media_02",
|
||||
"title": "Intro - The Way Of Waking Up (feat. Alan Watts - MP3)",
|
||||
"album": "Mixed media",
|
||||
"artist": "Mixed artists",
|
||||
"genre": "Mixed",
|
||||
"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/01_-_Intro_-_The_Way_Of_Waking_Up_feat_Alan_Watts.mp3",
|
||||
"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg"
|
||||
},
|
||||
{
|
||||
"id": "mixed_media_03",
|
||||
"title": "TTML Netflix Japanese examples (MP4)",
|
||||
"source": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/video-avc-baseline-480.mp4",
|
||||
"album": "Mixed media",
|
||||
"artist": "Mixed artists",
|
||||
"genre": "Mixed",
|
||||
"image": "https://cdn.pixabay.com/photo/2014/10/09/13/14/video-481821_960_720.png",
|
||||
"subtitles": [
|
||||
{
|
||||
"subtitle_uri": "https://storage.googleapis.com/exoplayer-test-media-1/ttml/netflix_japanese_ttml.xml",
|
||||
"subtitle_mime_type": "application/ttml+xml",
|
||||
"subtitle_lang": "ja"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "mixed_media_04",
|
||||
"title": "The Coldest Shoulder",
|
||||
"album": "Mixed media",
|
||||
"artist": "Mixed artists",
|
||||
"genre": "Mixed",
|
||||
"source": "https://storage.googleapis.com/automotive-media/The_Coldest_Shoulder.mp3",
|
||||
"image": "https://storage.googleapis.com/automotive-media/album_art_3.jpg"
|
||||
},
|
||||
{
|
||||
"id": "mixed_media_05",
|
||||
"title": "Dizzy - MPEG-4 Timed Text",
|
||||
"album": "Mixed media",
|
||||
"artist": "Mixed artists",
|
||||
"genre": "Mixed",
|
||||
"source": "https://storage.googleapis.com/exoplayer-test-media-1/mp4/dizzy-with-tx3g.mp4",
|
||||
"image": "https://cdn.pixabay.com/photo/2014/10/09/13/14/video-481821_960_720.png"
|
||||
},
|
||||
{
|
||||
"id": "mixed_media_06",
|
||||
"title": "Apple 4x3 basic stream (TS)",
|
||||
"album": "Mixed media",
|
||||
"artist": "Mixed artists",
|
||||
"genre": "Mixed",
|
||||
"source": "https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8",
|
||||
"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg"
|
||||
},
|
||||
{
|
||||
"id": "mixed_media_07",
|
||||
"title": "The Calm Before The Storm",
|
||||
"album": "Mixed media",
|
||||
"artist": "Mixed artists",
|
||||
"genre": "Mixed",
|
||||
"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/05_-_The_Calm_Before_The_Storm.mp3",
|
||||
"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg"
|
||||
},
|
||||
{
|
||||
"id": "mixed_media_08",
|
||||
"title": "Android screens (MKV)",
|
||||
"album": "Mixed media",
|
||||
"artist": "Mixed artists",
|
||||
"genre": "Mixed",
|
||||
"source": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv",
|
||||
"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg"
|
||||
},
|
||||
{
|
||||
"id": "mixed_media_09",
|
||||
"title": "No Pain, No Gain",
|
||||
"album": "Mixed media",
|
||||
"artist": "Mixed artists",
|
||||
"genre": "Mixed",
|
||||
"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/06_-_No_Pain_No_Gain.mp3",
|
||||
"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -93,10 +93,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
* The following attributes can be set on a PlayerView when used in a layout XML file:
|
||||
*
|
||||
* <ul>
|
||||
* <li><b>{@code use_artwork}</b> - Whether artwork is used if available in audio streams.
|
||||
* <li><b>{@code artwork_display_mode}</b> - Whether artwork is used if available in audio streams
|
||||
* and {@link ArtworkDisplayMode how it is displayed}.
|
||||
* <ul>
|
||||
* <li>Corresponding method: {@link #setUseArtwork(boolean)}
|
||||
* <li>Default: {@code true}
|
||||
* <li>Corresponding method: {@link #setArtworkDisplayMode(int)}
|
||||
* <li>Default: {@link #ARTWORK_DISPLAY_MODE_FIT}
|
||||
* </ul>
|
||||
* <li><b>{@code default_artwork}</b> - Default artwork to use if no artwork available in audio
|
||||
* streams.
|
||||
@ -201,6 +202,27 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
||||
void onFullscreenButtonClick(boolean isFullScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the artwork display mode. One of {@link #ARTWORK_DISPLAY_MODE_OFF}, {@link
|
||||
* #ARTWORK_DISPLAY_MODE_FIT} or {@link #ARTWORK_DISPLAY_MODE_FILL}.
|
||||
*/
|
||||
@UnstableApi
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target(TYPE_USE)
|
||||
@IntDef({ARTWORK_DISPLAY_MODE_OFF, ARTWORK_DISPLAY_MODE_FIT, ARTWORK_DISPLAY_MODE_FILL})
|
||||
public @interface ArtworkDisplayMode {}
|
||||
|
||||
/** No artwork is shown. */
|
||||
@UnstableApi public static final int ARTWORK_DISPLAY_MODE_OFF = 0;
|
||||
/** The artwork is fit into the player view and centered creating a letterbox style. */
|
||||
@UnstableApi public static final int ARTWORK_DISPLAY_MODE_FIT = 1;
|
||||
/**
|
||||
* The artwork covers the entire space of the player view. If the aspect ratio of the image is
|
||||
* different than the player view some areas of the image are cropped.
|
||||
*/
|
||||
@UnstableApi public static final int ARTWORK_DISPLAY_MODE_FILL = 2;
|
||||
|
||||
/**
|
||||
* Determines when the buffering view is shown. One of {@link #SHOW_BUFFERING_NEVER}, {@link
|
||||
* #SHOW_BUFFERING_WHEN_PLAYING} or {@link #SHOW_BUFFERING_ALWAYS}.
|
||||
@ -255,7 +277,8 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
||||
|
||||
@Nullable private FullscreenButtonClickListener fullscreenButtonClickListener;
|
||||
|
||||
private boolean useArtwork;
|
||||
private @ArtworkDisplayMode int artworkDisplayMode;
|
||||
|
||||
@Nullable private Drawable defaultArtwork;
|
||||
private @ShowBuffering int showBuffering;
|
||||
private boolean keepContentOnPlayerReset;
|
||||
@ -308,6 +331,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
||||
int shutterColor = 0;
|
||||
int playerLayoutId = R.layout.exo_player_view;
|
||||
boolean useArtwork = true;
|
||||
int artworkDisplayMode = ARTWORK_DISPLAY_MODE_FIT;
|
||||
int defaultArtworkId = 0;
|
||||
boolean useController = true;
|
||||
int surfaceType = SURFACE_TYPE_SURFACE_VIEW;
|
||||
@ -328,6 +352,8 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
||||
shutterColor = a.getColor(R.styleable.PlayerView_shutter_background_color, shutterColor);
|
||||
playerLayoutId = a.getResourceId(R.styleable.PlayerView_player_layout_id, playerLayoutId);
|
||||
useArtwork = a.getBoolean(R.styleable.PlayerView_use_artwork, useArtwork);
|
||||
artworkDisplayMode =
|
||||
a.getInt(R.styleable.PlayerView_artwork_display_mode, artworkDisplayMode);
|
||||
defaultArtworkId =
|
||||
a.getResourceId(R.styleable.PlayerView_default_artwork, defaultArtworkId);
|
||||
useController = a.getBoolean(R.styleable.PlayerView_use_controller, useController);
|
||||
@ -419,7 +445,9 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
||||
|
||||
// Artwork view.
|
||||
artworkView = findViewById(R.id.exo_artwork);
|
||||
this.useArtwork = useArtwork && artworkView != null;
|
||||
boolean isArtworkEnabled =
|
||||
useArtwork && artworkDisplayMode != ARTWORK_DISPLAY_MODE_OFF && artworkView != null;
|
||||
this.artworkDisplayMode = isArtworkEnabled ? artworkDisplayMode : ARTWORK_DISPLAY_MODE_OFF;
|
||||
if (defaultArtworkId != 0) {
|
||||
defaultArtwork = ContextCompat.getDrawable(getContext(), defaultArtworkId);
|
||||
}
|
||||
@ -556,7 +584,10 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
||||
} else if (surfaceView instanceof SurfaceView) {
|
||||
player.setVideoSurfaceView((SurfaceView) surfaceView);
|
||||
}
|
||||
updateAspectRatio();
|
||||
if (player.getCurrentTracks().isTypeSupported(C.TRACK_TYPE_VIDEO)) {
|
||||
// If the player already is or was playing a video, onVideoSizeChanged isn't called.
|
||||
updateAspectRatio();
|
||||
}
|
||||
}
|
||||
if (subtitleView != null && player.isCommandAvailable(COMMAND_GET_TEXT)) {
|
||||
subtitleView.setCues(player.getCurrentCues().cues);
|
||||
@ -595,26 +626,40 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
||||
return contentFrame.getResizeMode();
|
||||
}
|
||||
|
||||
/** Returns whether artwork is displayed if present in the media. */
|
||||
/**
|
||||
* @deprecated Use {@link #getArtworkDisplayMode()} instead.
|
||||
*/
|
||||
@UnstableApi
|
||||
@Deprecated
|
||||
public boolean getUseArtwork() {
|
||||
return useArtwork;
|
||||
return this.artworkDisplayMode != ARTWORK_DISPLAY_MODE_OFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether artwork is displayed if present in the media.
|
||||
*
|
||||
* @param useArtwork Whether artwork is displayed.
|
||||
* @deprecated Use {@link #setArtworkDisplayMode(int)} instead.
|
||||
*/
|
||||
@UnstableApi
|
||||
@Deprecated
|
||||
public void setUseArtwork(boolean useArtwork) {
|
||||
Assertions.checkState(!useArtwork || artworkView != null);
|
||||
if (this.useArtwork != useArtwork) {
|
||||
this.useArtwork = useArtwork;
|
||||
setArtworkDisplayMode(useArtwork ? ARTWORK_DISPLAY_MODE_OFF : ARTWORK_DISPLAY_MODE_FIT);
|
||||
}
|
||||
|
||||
/** Sets whether and how artwork is displayed if present in the media. */
|
||||
@UnstableApi
|
||||
public void setArtworkDisplayMode(@ArtworkDisplayMode int artworkDisplayMode) {
|
||||
Assertions.checkState(artworkDisplayMode == ARTWORK_DISPLAY_MODE_OFF || artworkView != null);
|
||||
if (this.artworkDisplayMode != artworkDisplayMode) {
|
||||
this.artworkDisplayMode = artworkDisplayMode;
|
||||
updateForCurrentTrackSelections(/* isNewPlayer= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the {@link ArtworkDisplayMode artwork display mode}. */
|
||||
@UnstableApi
|
||||
public @ArtworkDisplayMode int getArtworkDisplayMode() {
|
||||
return artworkDisplayMode;
|
||||
}
|
||||
|
||||
/** Returns the default artwork to display. */
|
||||
@UnstableApi
|
||||
@Nullable
|
||||
@ -1243,7 +1288,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
||||
|
||||
@EnsuresNonNullIf(expression = "artworkView", result = true)
|
||||
private boolean useArtwork() {
|
||||
if (useArtwork) {
|
||||
if (artworkDisplayMode != ARTWORK_DISPLAY_MODE_OFF) {
|
||||
Assertions.checkStateNotNull(artworkView);
|
||||
return true;
|
||||
}
|
||||
@ -1364,8 +1409,14 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
|
||||
int drawableWidth = drawable.getIntrinsicWidth();
|
||||
int drawableHeight = drawable.getIntrinsicHeight();
|
||||
if (drawableWidth > 0 && drawableHeight > 0) {
|
||||
float artworkAspectRatio = (float) drawableWidth / drawableHeight;
|
||||
onContentAspectRatioChanged(contentFrame, artworkAspectRatio);
|
||||
float artworkLayoutAspectRatio = (float) drawableWidth / drawableHeight;
|
||||
ImageView.ScaleType scaleStyle = ImageView.ScaleType.FIT_XY;
|
||||
if (artworkDisplayMode == ARTWORK_DISPLAY_MODE_FILL) {
|
||||
artworkLayoutAspectRatio = (float) getWidth() / getHeight();
|
||||
scaleStyle = ImageView.ScaleType.CENTER_CROP;
|
||||
}
|
||||
onContentAspectRatioChanged(contentFrame, artworkLayoutAspectRatio);
|
||||
artworkView.setScaleType(scaleStyle);
|
||||
artworkView.setImageDrawable(drawable);
|
||||
artworkView.setVisibility(VISIBLE);
|
||||
return true;
|
||||
|
@ -42,6 +42,11 @@
|
||||
|
||||
<!-- LegacyPlayerView and PlayerView attributes -->
|
||||
<attr name="use_artwork" format="boolean"/>
|
||||
<attr name="artwork_display_mode" format="enum">
|
||||
<enum name="off" value="0"/>
|
||||
<enum name="fit" value="1"/>
|
||||
<enum name="fill" value="2"/>
|
||||
</attr>
|
||||
<attr name="shutter_background_color" format="color"/>
|
||||
<attr name="default_artwork" format="reference"/>
|
||||
<attr name="use_controller" format="boolean"/>
|
||||
@ -93,6 +98,7 @@
|
||||
|
||||
<declare-styleable name="PlayerView">
|
||||
<attr name="use_artwork"/>
|
||||
<attr name="artwork_display_mode"/>
|
||||
<attr name="shutter_background_color"/>
|
||||
<attr name="default_artwork"/>
|
||||
<attr name="use_controller"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user