mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
[ui-compose] Rename showSurface to coverSurface in PresentationState
This renaming helps prevent the consumer from including `PlayerSurface` in a Compose tree based on `state.showSurface`. This field intuitively felt like the default would be not to show the surface (correct), but had an unintended consequence of not initialising `AndroidExternal(Embedded)Surface` (since the PlayerSurface Composable would be omitted). To avoid this confusion, the `PresentationState` should communicate to the consumer when the Surface is not ready and hence should be covered with some overlay (shutter) to prevent poor UX from observing Surface resizing/freezing/flickering. PiperOrigin-RevId: 714951607
This commit is contained in:
parent
d18ad57e30
commit
52387bb975
@ -114,17 +114,21 @@ private fun MediaPlayerScreen(player: Player, modifier: Modifier = Modifier) {
|
||||
val presentationState = rememberPresentationState(player)
|
||||
val scaledModifier = Modifier.resizeWithContentScale(contentScale, presentationState.videoSizeDp)
|
||||
|
||||
// Only use MediaPlayerScreen's modifier once for the top level Composable
|
||||
Box(modifier) {
|
||||
// Always leave PlayerSurface to be part of the Compose tree because it will be initialised in
|
||||
// the process. If this composable is guarded by some condition, it might never become visible
|
||||
// because the Player will not emit the relevant event, e.g. the first frame being ready.
|
||||
PlayerSurface(
|
||||
player = player,
|
||||
surfaceType = SURFACE_TYPE_SURFACE_VIEW,
|
||||
modifier = scaledModifier.noRippleClickable { showControls = !showControls },
|
||||
)
|
||||
|
||||
if (!presentationState.showSurface) {
|
||||
// hide the surface that is being prepared behind a shutter
|
||||
// TODO: picking scaledModifier here makes the shutter invisible
|
||||
Box(modifier.background(Color.Black))
|
||||
if (presentationState.coverSurface) {
|
||||
// Cover the surface that is being prepared with a shutter
|
||||
// Do not use scaledModifier here, makes the Box be measured at 0x0
|
||||
Box(Modifier.matchParentSize().background(Color.Black))
|
||||
}
|
||||
|
||||
if (showControls) {
|
||||
|
@ -57,8 +57,9 @@ fun rememberPresentationState(player: Player): PresentationState {
|
||||
* [Density.toPx]. Note that for cases where `pixelWidthHeightRatio` is not equal to 1, the
|
||||
* rescaling will be down, i.e. reducing the width or the height to achieve the same aspect ratio
|
||||
* in square pixels.
|
||||
* @property[showSurface] set to true when the Player emits [Player.EVENT_RENDERED_FIRST_FRAME] and
|
||||
* reset to false on [Player.EVENT_TRACKS_CHANGED] depending on the number and type of tracks.
|
||||
* @property[coverSurface] set to false when the Player emits [Player.EVENT_RENDERED_FIRST_FRAME]
|
||||
* and reset back to true on [Player.EVENT_TRACKS_CHANGED] depending on the number and type of
|
||||
* tracks.
|
||||
* @property[keepContentOnReset] whether the currently displayed video frame or media artwork is
|
||||
* kept visible when tracks change. Defaults to false.
|
||||
*/
|
||||
@ -67,7 +68,7 @@ class PresentationState(private val player: Player) {
|
||||
var videoSizeDp: Size? by mutableStateOf(getVideoSizeDp(player))
|
||||
private set
|
||||
|
||||
var showSurface by mutableStateOf(false)
|
||||
var coverSurface by mutableStateOf(true)
|
||||
private set
|
||||
|
||||
var keepContentOnReset: Boolean = false
|
||||
@ -86,7 +87,8 @@ class PresentationState(private val player: Player) {
|
||||
}
|
||||
}
|
||||
if (events.contains(Player.EVENT_RENDERED_FIRST_FRAME)) {
|
||||
showSurface = true
|
||||
// open shutter, video available
|
||||
coverSurface = false
|
||||
}
|
||||
if (events.contains(Player.EVENT_TRACKS_CHANGED)) {
|
||||
maybeHideSurface(player)
|
||||
@ -112,17 +114,17 @@ class PresentationState(private val player: Player) {
|
||||
player.isCommandAvailable(Player.COMMAND_GET_TRACKS) && !player.currentTracks.isEmpty
|
||||
if (!shouldKeepSurfaceVisible(player)) {
|
||||
if (!keepContentOnReset && !hasTracks) {
|
||||
showSurface = false
|
||||
coverSurface = true
|
||||
}
|
||||
if (hasTracks && !hasSelectedVideoTrack()) {
|
||||
showSurface = false
|
||||
coverSurface = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldKeepSurfaceVisible(player: Player): Boolean {
|
||||
// Suppress the shutter if transitioning to an unprepared period within the same window. This
|
||||
// is necessary to avoid closing the shutter (i.e hiding the surface) when such a transition
|
||||
// is necessary to avoid closing the shutter (i.e covering the surface) when such a transition
|
||||
// occurs. See: https://github.com/google/ExoPlayer/issues/5507.
|
||||
val timeline =
|
||||
if (player.isCommandAvailable(Player.COMMAND_GET_TIMELINE)) player.currentTimeline
|
||||
|
Loading…
x
Reference in New Issue
Block a user