StyledPlayerControlView: Fixes for minimal mode

- Re-layer layout so that the central controls end up on
  top (and, more importantly, have preference for receiving
  touch input) if the view is so small that elements start
  to overlap. This requires splitting the background and
  the controls themselves.
- Fix bug that could cause the scrubber to not be hidden
  in minimal mode, if the mode is entered when the controls
  are not visible.
- Fix positioning of minimal controls.
- Remove scrubber padding in minimal mode, since the scrubber
- Remove unused bar_gravity value.

PiperOrigin-RevId: 347008789
This commit is contained in:
olly 2020-12-11 17:01:02 +00:00 committed by Ian Baker
parent 7d478a9f5a
commit 2accb41ef6
6 changed files with 94 additions and 73 deletions

View file

@ -27,6 +27,7 @@
* Add option to specify multiple preferred audio or text languages.
* Forward `Timeline` and `MediaPeriodId` to `TrackSelection.Factory`.
* UI:
* Miscellaneous fixes for `StyledPlayerControlView` in minimal mode.
* Show overflow button in `StyledPlayerControlView` only when there is not
enough space.
* Update StyledPlayer's control overlay scrim from 30% opacity to 60%

View file

@ -157,8 +157,6 @@ public class DefaultTimeBar extends View implements TimeBar {
public static final int BAR_GRAVITY_CENTER = 0;
/** Vertical gravity for progress bar to be located at the bottom in the view. */
public static final int BAR_GRAVITY_BOTTOM = 1;
/** Vertical gravity for progress bar to be located at the top in the view. */
public static final int BAR_GRAVITY_TOP = 2;
// LINT.ThenChange(../../../../../../../../../ui/src/main/res/values/attrs.xml)
/** The threshold in dps above the bar at which touch events trigger fine scrub mode. */
@ -216,6 +214,7 @@ public class DefaultTimeBar extends View implements TimeBar {
private ValueAnimator scrubberScalingAnimator;
private float scrubberScale;
private boolean scrubberPaddingDisabled;
private boolean scrubbing;
private long scrubPosition;
private long duration;
@ -370,7 +369,12 @@ public class DefaultTimeBar extends View implements TimeBar {
/** Shows the scrubber handle. */
public void showScrubber() {
showScrubber(/* showAnimationDurationMs= */ 0);
if (scrubberScalingAnimator.isStarted()) {
scrubberScalingAnimator.cancel();
}
scrubberPaddingDisabled = false;
scrubberScale = 1;
invalidate(seekBounds);
}
/**
@ -382,14 +386,20 @@ public class DefaultTimeBar extends View implements TimeBar {
if (scrubberScalingAnimator.isStarted()) {
scrubberScalingAnimator.cancel();
}
scrubberPaddingDisabled = false;
scrubberScalingAnimator.setFloatValues(scrubberScale, SHOWN_SCRUBBER_SCALE);
scrubberScalingAnimator.setDuration(showAnimationDurationMs);
scrubberScalingAnimator.start();
}
/** Hides the scrubber handle. */
public void hideScrubber() {
hideScrubber(/* hideAnimationDurationMs= */ 0);
public void hideScrubber(boolean disableScrubberPadding) {
if (scrubberScalingAnimator.isStarted()) {
scrubberScalingAnimator.cancel();
}
scrubberPaddingDisabled = disableScrubberPadding;
scrubberScale = 0;
invalidate(seekBounds);
}
/**
@ -668,20 +678,25 @@ public class DefaultTimeBar extends View implements TimeBar {
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int width = right - left;
int height = bottom - top;
int barY = (height - touchTargetHeight) / 2;
int seekLeft = getPaddingLeft();
int seekRight = width - getPaddingRight();
int progressY;
int seekBoundsY;
int progressBarY;
int scrubberPadding = scrubberPaddingDisabled ? 0 : this.scrubberPadding;
if (barGravity == BAR_GRAVITY_BOTTOM) {
progressY = barY + touchTargetHeight - (getPaddingBottom() + scrubberPadding + barHeight / 2);
} else if (barGravity == BAR_GRAVITY_TOP) {
progressY = barY + getPaddingTop() + scrubberPadding - barHeight / 2;
seekBoundsY = height - getPaddingBottom() - touchTargetHeight;
progressBarY =
height - getPaddingBottom() - barHeight - Math.max(scrubberPadding - (barHeight / 2), 0);
} else {
progressY = barY + (touchTargetHeight - barHeight) / 2;
seekBoundsY = (height - touchTargetHeight) / 2;
progressBarY = (height - barHeight) / 2;
}
seekBounds.set(seekLeft, barY, seekRight, barY + touchTargetHeight);
progressBar.set(seekBounds.left + scrubberPadding, progressY,
seekBounds.right - scrubberPadding, progressY + barHeight);
seekBounds.set(seekLeft, seekBoundsY, seekRight, seekBoundsY + touchTargetHeight);
progressBar.set(
seekBounds.left + scrubberPadding,
progressBarY,
seekBounds.right - scrubberPadding,
progressBarY + barHeight);
if (Util.SDK_INT >= 29) {
setSystemGestureExclusionRectsV29(width, height);
}

View file

@ -98,7 +98,7 @@ import java.util.List;
shownButtons = new ArrayList<>();
// Relating to Center View
ViewGroup centerView = styledPlayerControlView.findViewById(R.id.exo_center_view);
View controlsBackground = styledPlayerControlView.findViewById(R.id.exo_controls_background);
centerControls = styledPlayerControlView.findViewById(R.id.exo_center_controls);
// Relating to Minimal Layout
@ -137,8 +137,11 @@ import java.util.List;
fadeOutAnimator.addUpdateListener(
animation -> {
float animatedValue = (float) animation.getAnimatedValue();
if (centerView != null) {
centerView.setAlpha(animatedValue);
if (controlsBackground != null) {
controlsBackground.setAlpha(animatedValue);
}
if (centerControls != null) {
centerControls.setAlpha(animatedValue);
}
if (minimalControls != null) {
minimalControls.setAlpha(animatedValue);
@ -155,8 +158,11 @@ import java.util.List;
@Override
public void onAnimationEnd(Animator animation) {
if (centerView != null) {
centerView.setVisibility(View.INVISIBLE);
if (controlsBackground != null) {
controlsBackground.setVisibility(View.INVISIBLE);
}
if (centerControls != null) {
centerControls.setVisibility(View.INVISIBLE);
}
if (minimalControls != null) {
minimalControls.setVisibility(View.INVISIBLE);
@ -169,8 +175,11 @@ import java.util.List;
fadeInAnimator.addUpdateListener(
animation -> {
float animatedValue = (float) animation.getAnimatedValue();
if (centerView != null) {
centerView.setAlpha(animatedValue);
if (controlsBackground != null) {
controlsBackground.setAlpha(animatedValue);
}
if (centerControls != null) {
centerControls.setAlpha(animatedValue);
}
if (minimalControls != null) {
minimalControls.setAlpha(animatedValue);
@ -180,8 +189,11 @@ import java.util.List;
new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
if (centerView != null) {
centerView.setVisibility(View.VISIBLE);
if (controlsBackground != null) {
controlsBackground.setVisibility(View.VISIBLE);
}
if (centerControls != null) {
centerControls.setVisibility(View.VISIBLE);
}
if (minimalControls != null) {
minimalControls.setVisibility(isMinimalMode ? View.VISIBLE : View.INVISIBLE);
@ -595,13 +607,14 @@ import java.util.List;
.getDimensionPixelSize(R.dimen.exo_styled_progress_margin_bottom);
timeBarParams.bottomMargin = (isMinimalMode ? 0 : timeBarMarginBottom);
timeBar.setLayoutParams(timeBarParams);
if (timeBar instanceof DefaultTimeBar
&& uxState != UX_STATE_ANIMATING_HIDE
&& uxState != UX_STATE_ANIMATING_SHOW) {
if (isMinimalMode || uxState != UX_STATE_ALL_VISIBLE) {
((DefaultTimeBar) timeBar).hideScrubber();
} else {
((DefaultTimeBar) timeBar).showScrubber();
if (timeBar instanceof DefaultTimeBar) {
DefaultTimeBar defaultTimeBar = (DefaultTimeBar) timeBar;
if (isMinimalMode) {
defaultTimeBar.hideScrubber(/* disableScrubberPadding= */ true);
} else if (uxState == UX_STATE_ONLY_PROGRESS_VISIBLE) {
defaultTimeBar.hideScrubber(/* disableScrubberPadding= */ false);
} else if (uxState != UX_STATE_ANIMATING_HIDE && uxState != UX_STATE_ANIMATING_SHOW) {
defaultTimeBar.showScrubber();
}
}
}

View file

@ -15,42 +15,11 @@
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout android:id="@+id/exo_center_view"
<View android:id="@+id/exo_controls_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layoutDirection="ltr">
<View android:id="@+id/exo_center_view_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@color/exo_black_opacity_60"/>
<LinearLayout android:id="@+id/exo_center_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center">
<ImageButton android:id="@+id/exo_prev"
style="@style/ExoStyledControls.Button.Center.Previous"/>
<Button android:id="@+id/exo_rew_with_amount"
style="@style/ExoStyledControls.Button.Center.RewWithAmount"/>
<ImageButton android:id="@+id/exo_play_pause"
style="@style/ExoStyledControls.Button.Center.PlayPause"/>
<Button android:id="@+id/exo_ffwd_with_amount"
style="@style/ExoStyledControls.Button.Center.FfwdWithAmount"/>
<ImageButton android:id="@+id/exo_next"
style="@style/ExoStyledControls.Button.Center.Next"/>
</LinearLayout>
</FrameLayout>
android:background="@color/exo_black_opacity_60"/>
<FrameLayout android:id="@+id/exo_bottom_bar"
android:layout_width="match_parent"
@ -84,7 +53,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:orientation="horizontal"
android:layoutDirection="ltr">
<ImageButton android:id="@+id/exo_shuffle"
@ -130,18 +98,42 @@
</FrameLayout>
<LinearLayout android:id="@+id/exo_minimal_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="bottom|end"
android:layout_marginBottom="@dimen/exo_styled_progress_layout_height"
android:visibility="invisible"/>
<View android:id="@+id/exo_progress_placeholder"
android:layout_width="match_parent"
android:layout_height="@dimen/exo_styled_progress_layout_height"
android:layout_gravity="bottom"
android:layout_marginBottom="@dimen/exo_styled_progress_margin_bottom"/>
<LinearLayout android:id="@+id/exo_minimal_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="@dimen/exo_styled_minimal_controls_margin_bottom"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layoutDirection="ltr"/>
<LinearLayout android:id="@+id/exo_center_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center">
<ImageButton android:id="@+id/exo_prev"
style="@style/ExoStyledControls.Button.Center.Previous"/>
<Button android:id="@+id/exo_rew_with_amount"
style="@style/ExoStyledControls.Button.Center.RewWithAmount"/>
<ImageButton android:id="@+id/exo_play_pause"
style="@style/ExoStyledControls.Button.Center.PlayPause"/>
<Button android:id="@+id/exo_ffwd_with_amount"
style="@style/ExoStyledControls.Button.Center.FfwdWithAmount"/>
<ImageButton android:id="@+id/exo_next"
style="@style/ExoStyledControls.Button.Center.Next"/>
</LinearLayout>
</merge>

View file

@ -80,7 +80,6 @@
<attr name="bar_gravity" format="enum">
<enum name="center" value="0"/>
<enum name="bottom" value="1"/>
<enum name="top" value="2"/>
</attr>
<attr name="touch_target_height" format="dimension"/>
<attr name="ad_marker_width" format="dimension"/>

View file

@ -43,6 +43,7 @@
<dimen name="exo_styled_progress_margin_bottom">52dp</dimen>
<dimen name="exo_styled_bottom_bar_height">60dp</dimen>
<dimen name="exo_styled_time_padding">10dp</dimen>
<dimen name="exo_styled_minimal_controls_margin_bottom">4dp</dimen>
<dimen name="exo_error_message_height">32dp</dimen>
<dimen name="exo_error_message_margin_bottom">64dp</dimen>