Skip to content

Commit 2b66c41

Browse files
toniheitianyif
authored andcommitted
Show play button during playback suppression by default
This changes the default logic of shouldShowPlayButton to show a play button while the playback is temporarily suppressed. This helps to provide better UI feedback to the fact that playback stopped and provides a quick way for users to override the suppression and attempt to restart playback. Some apps may want to keep the legacy behavior depending on their app's needs. Hence, we also add a config parameter to set this behavior both in MediaSession and our default UI components. Issue: #11213 PiperOrigin-RevId: 557129171
1 parent 9cf8eb8 commit 2b66c41

File tree

6 files changed

+130
-18
lines changed

6 files changed

+130
-18
lines changed

library/common/src/main/java/com/google/android/exoplayer2/util/Util.java

+43-9
Original file line numberDiff line numberDiff line change
@@ -3043,23 +3043,41 @@ public static String intToStringMaxRadix(int i) {
30433043
* <p>Use {@link #handlePlayPauseButtonAction}, {@link #handlePlayButtonAction} or {@link
30443044
* #handlePauseButtonAction} to handle the interaction with the play or pause button UI element.
30453045
*
3046-
* @param player The {@link Player}. May be null.
3046+
* @param player The {@link Player}. May be {@code null}.
30473047
*/
30483048
@EnsuresNonNullIf(result = false, expression = "#1")
30493049
public static boolean shouldShowPlayButton(@Nullable Player player) {
3050+
return shouldShowPlayButton(player, /* playIfSuppressed= */ true);
3051+
}
3052+
3053+
/**
3054+
* Returns whether a play button should be presented on a UI element for playback control. If
3055+
* {@code false}, a pause button should be shown instead.
3056+
*
3057+
* <p>Use {@link #handlePlayPauseButtonAction}, {@link #handlePlayButtonAction} or {@link
3058+
* #handlePauseButtonAction} to handle the interaction with the play or pause button UI element.
3059+
*
3060+
* @param player The {@link Player}. May be {@code null}.
3061+
* @param playIfSuppressed Whether to show a play button if playback is {@linkplain
3062+
* Player#getPlaybackSuppressionReason() suppressed}.
3063+
*/
3064+
@EnsuresNonNullIf(result = false, expression = "#1")
3065+
public static boolean shouldShowPlayButton(@Nullable Player player, boolean playIfSuppressed) {
30503066
return player == null
30513067
|| !player.getPlayWhenReady()
30523068
|| player.getPlaybackState() == Player.STATE_IDLE
3053-
|| player.getPlaybackState() == Player.STATE_ENDED;
3069+
|| player.getPlaybackState() == Player.STATE_ENDED
3070+
|| (playIfSuppressed
3071+
&& player.getPlaybackSuppressionReason() != Player.PLAYBACK_SUPPRESSION_REASON_NONE);
30543072
}
30553073

30563074
/**
30573075
* Updates the player to handle an interaction with a play button.
30583076
*
30593077
* <p>This method assumes the play button is enabled if {@link #shouldShowPlayButton} returns
3060-
* true.
3078+
* {@code true}.
30613079
*
3062-
* @param player The {@link Player}. May be null.
3080+
* @param player The {@link Player}. May be {@code null}.
30633081
* @return Whether a player method was triggered to handle this action.
30643082
*/
30653083
public static boolean handlePlayButtonAction(@Nullable Player player) {
@@ -3087,9 +3105,9 @@ public static boolean handlePlayButtonAction(@Nullable Player player) {
30873105
* Updates the player to handle an interaction with a pause button.
30883106
*
30893107
* <p>This method assumes the pause button is enabled if {@link #shouldShowPlayButton} returns
3090-
* false.
3108+
* {@code false}.
30913109
*
3092-
* @param player The {@link Player}. May be null.
3110+
* @param player The {@link Player}. May be {@code null}.
30933111
* @return Whether a player method was triggered to handle this action.
30943112
*/
30953113
public static boolean handlePauseButtonAction(@Nullable Player player) {
@@ -3104,13 +3122,29 @@ public static boolean handlePauseButtonAction(@Nullable Player player) {
31043122
* Updates the player to handle an interaction with a play or pause button.
31053123
*
31063124
* <p>This method assumes that the UI element enables a play button if {@link
3107-
* #shouldShowPlayButton} returns true and a pause button otherwise.
3125+
* #shouldShowPlayButton} returns {@code true} and a pause button otherwise.
31083126
*
3109-
* @param player The {@link Player}. May be null.
3127+
* @param player The {@link Player}. May be {@code null}.
31103128
* @return Whether a player method was triggered to handle this action.
31113129
*/
31123130
public static boolean handlePlayPauseButtonAction(@Nullable Player player) {
3113-
if (shouldShowPlayButton(player)) {
3131+
return handlePlayPauseButtonAction(player, /* playIfSuppressed= */ true);
3132+
}
3133+
3134+
/**
3135+
* Updates the player to handle an interaction with a play or pause button.
3136+
*
3137+
* <p>This method assumes that the UI element enables a play button if {@link
3138+
* #shouldShowPlayButton(Player, boolean)} returns {@code true} and a pause button otherwise.
3139+
*
3140+
* @param player The {@link Player}. May be {@code null}.
3141+
* @param playIfSuppressed Whether to trigger a play action if playback is {@linkplain
3142+
* Player#getPlaybackSuppressionReason() suppressed}.
3143+
* @return Whether a player method was triggered to handle this action.
3144+
*/
3145+
public static boolean handlePlayPauseButtonAction(
3146+
@Nullable Player player, boolean playIfSuppressed) {
3147+
if (shouldShowPlayButton(player, playIfSuppressed)) {
31143148
return handlePlayButtonAction(player);
31153149
} else {
31163150
return handlePauseButtonAction(player);

library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java

+20-4
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ public interface ProgressUpdateListener {
332332

333333
private boolean isAttachedToWindow;
334334
private boolean showMultiWindowTimeBar;
335+
private boolean showPlayButtonIfSuppressed;
335336
private boolean multiWindowTimeBar;
336337
private boolean scrubbing;
337338
private int showTimeoutMs;
@@ -375,6 +376,7 @@ public PlayerControlView(
375376
@Nullable AttributeSet playbackAttrs) {
376377
super(context, attrs, defStyleAttr);
377378
int controllerLayoutId = R.layout.exo_player_control_view;
379+
showPlayButtonIfSuppressed = true;
378380
showTimeoutMs = DEFAULT_SHOW_TIMEOUT_MS;
379381
repeatToggleModes = DEFAULT_REPEAT_TOGGLE_MODES;
380382
timeBarMinUpdateIntervalMs = DEFAULT_TIME_BAR_MIN_UPDATE_INTERVAL_MS;
@@ -562,6 +564,20 @@ public void setShowMultiWindowTimeBar(boolean showMultiWindowTimeBar) {
562564
updateTimeline();
563565
}
564566

567+
/**
568+
* Sets whether a play button is shown if playback is {@linkplain
569+
* Player#getPlaybackSuppressionReason() suppressed}.
570+
*
571+
* <p>The default is {@code true}.
572+
*
573+
* @param showPlayButtonIfSuppressed Whether to show a play button if playback is {@linkplain
574+
* Player#getPlaybackSuppressionReason() suppressed}.
575+
*/
576+
public void setShowPlayButtonIfPlaybackIsSuppressed(boolean showPlayButtonIfSuppressed) {
577+
this.showPlayButtonIfSuppressed = showPlayButtonIfSuppressed;
578+
updatePlayPauseButton();
579+
}
580+
565581
/**
566582
* Sets the millisecond positions of extra ad markers relative to the start of the window (or
567583
* timeline, if in multi-window mode) and whether each extra ad has been played or not. The
@@ -833,7 +849,7 @@ private void updatePlayPauseButton() {
833849
}
834850
boolean requestPlayPauseFocus = false;
835851
boolean requestPlayPauseAccessibilityFocus = false;
836-
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
852+
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player, showPlayButtonIfSuppressed);
837853
if (playButton != null) {
838854
requestPlayPauseFocus |= !shouldShowPlayButton && playButton.isFocused();
839855
requestPlayPauseAccessibilityFocus |=
@@ -1074,7 +1090,7 @@ private void updateProgress() {
10741090
}
10751091

10761092
private void requestPlayPauseFocus() {
1077-
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
1093+
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player, showPlayButtonIfSuppressed);
10781094
if (shouldShowPlayButton && playButton != null) {
10791095
playButton.requestFocus();
10801096
} else if (!shouldShowPlayButton && pauseButton != null) {
@@ -1083,7 +1099,7 @@ private void requestPlayPauseFocus() {
10831099
}
10841100

10851101
private void requestPlayPauseAccessibilityFocus() {
1086-
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
1102+
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player, showPlayButtonIfSuppressed);
10871103
if (shouldShowPlayButton && playButton != null) {
10881104
playButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
10891105
} else if (!shouldShowPlayButton && pauseButton != null) {
@@ -1193,7 +1209,7 @@ public boolean dispatchMediaKeyEvent(KeyEvent event) {
11931209
switch (keyCode) {
11941210
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
11951211
case KeyEvent.KEYCODE_HEADSETHOOK:
1196-
Util.handlePlayPauseButtonAction(player);
1212+
Util.handlePlayPauseButtonAction(player, showPlayButtonIfSuppressed);
11971213
break;
11981214
case KeyEvent.KEYCODE_MEDIA_PLAY:
11991215
Util.handlePlayButtonAction(player);

library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java

+20-2
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,7 @@ public void onBitmap(final Bitmap bitmap) {
716716
private boolean useRewindActionInCompactView;
717717
private boolean useFastForwardActionInCompactView;
718718
private boolean usePlayPauseActions;
719+
private boolean showPlayButtonIfSuppressed;
719720
private boolean useStopAction;
720721
private int badgeIconType;
721722
private boolean colorized;
@@ -766,6 +767,7 @@ protected PlayerNotificationManager(
766767
usePreviousAction = true;
767768
useNextAction = true;
768769
usePlayPauseActions = true;
770+
showPlayButtonIfSuppressed = true;
769771
useRewindAction = true;
770772
useFastForwardAction = true;
771773
colorized = true;
@@ -975,6 +977,22 @@ public final void setUsePlayPauseActions(boolean usePlayPauseActions) {
975977
}
976978
}
977979

980+
/**
981+
* Sets whether a play button is shown if playback is {@linkplain
982+
* Player#getPlaybackSuppressionReason() suppressed}.
983+
*
984+
* <p>The default is {@code true}.
985+
*
986+
* @param showPlayButtonIfSuppressed Whether to show a play button if playback is {@linkplain
987+
* Player#getPlaybackSuppressionReason() suppressed}.
988+
*/
989+
public void setShowPlayButtonIfPlaybackIsSuppressed(boolean showPlayButtonIfSuppressed) {
990+
if (this.showPlayButtonIfSuppressed != showPlayButtonIfSuppressed) {
991+
this.showPlayButtonIfSuppressed = showPlayButtonIfSuppressed;
992+
invalidate();
993+
}
994+
}
995+
978996
/**
979997
* Sets whether the stop action should be used.
980998
*
@@ -1343,7 +1361,7 @@ protected List<String> getActions(Player player) {
13431361
stringActions.add(ACTION_REWIND);
13441362
}
13451363
if (usePlayPauseActions) {
1346-
if (Util.shouldShowPlayButton(player)) {
1364+
if (Util.shouldShowPlayButton(player, showPlayButtonIfSuppressed)) {
13471365
stringActions.add(ACTION_PLAY);
13481366
} else {
13491367
stringActions.add(ACTION_PAUSE);
@@ -1391,7 +1409,7 @@ protected int[] getActionIndicesForCompactView(List<String> actionNames, Player
13911409
if (leftSideActionIndex != -1) {
13921410
actionIndices[actionCounter++] = leftSideActionIndex;
13931411
}
1394-
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
1412+
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player, showPlayButtonIfSuppressed);
13951413
if (pauseActionIndex != -1 && !shouldShowPlayButton) {
13961414
actionIndices[actionCounter++] = pauseActionIndex;
13971415
} else if (playActionIndex != -1 && shouldShowPlayButton) {

library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java

+14
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,20 @@ public void setShowMultiWindowTimeBar(boolean showMultiWindowTimeBar) {
10101010
controller.setShowMultiWindowTimeBar(showMultiWindowTimeBar);
10111011
}
10121012

1013+
/**
1014+
* Sets whether a play button is shown if playback is {@linkplain
1015+
* Player#getPlaybackSuppressionReason() suppressed}.
1016+
*
1017+
* <p>The default is {@code true}.
1018+
*
1019+
* @param showPlayButtonIfSuppressed Whether to show a play button if playback is {@linkplain
1020+
* Player#getPlaybackSuppressionReason() suppressed}.
1021+
*/
1022+
public void setShowPlayButtonIfPlaybackIsSuppressed(boolean showPlayButtonIfSuppressed) {
1023+
Assertions.checkStateNotNull(controller);
1024+
controller.setShowPlayButtonIfPlaybackIsSuppressed(showPlayButtonIfSuppressed);
1025+
}
1026+
10131027
/**
10141028
* Sets the millisecond positions of extra ad markers relative to the start of the window (or
10151029
* timeline, if in multi-window mode) and whether each extra ad has been played or not. The

library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java

+19-3
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ public interface OnFullScreenModeChangedListener {
339339
private boolean isFullScreen;
340340
private boolean isAttachedToWindow;
341341
private boolean showMultiWindowTimeBar;
342+
private boolean showPlayButtonIfSuppressed;
342343
private boolean multiWindowTimeBar;
343344
private boolean scrubbing;
344345
private int showTimeoutMs;
@@ -377,6 +378,7 @@ public StyledPlayerControlView(
377378
@Nullable AttributeSet playbackAttrs) {
378379
super(context, attrs, defStyleAttr);
379380
int controllerLayoutId = R.layout.exo_styled_player_control_view;
381+
showPlayButtonIfSuppressed = true;
380382
showTimeoutMs = DEFAULT_SHOW_TIMEOUT_MS;
381383
repeatToggleModes = DEFAULT_REPEAT_TOGGLE_MODES;
382384
timeBarMinUpdateIntervalMs = DEFAULT_TIME_BAR_MIN_UPDATE_INTERVAL_MS;
@@ -685,6 +687,20 @@ public void setShowMultiWindowTimeBar(boolean showMultiWindowTimeBar) {
685687
updateTimeline();
686688
}
687689

690+
/**
691+
* Sets whether a play button is shown if playback is {@linkplain
692+
* Player#getPlaybackSuppressionReason() suppressed}.
693+
*
694+
* <p>The default is {@code true}.
695+
*
696+
* @param showPlayButtonIfSuppressed Whether to show a play button if playback is {@linkplain
697+
* Player#getPlaybackSuppressionReason() suppressed}.
698+
*/
699+
public void setShowPlayButtonIfPlaybackIsSuppressed(boolean showPlayButtonIfSuppressed) {
700+
this.showPlayButtonIfSuppressed = showPlayButtonIfSuppressed;
701+
updatePlayPauseButton();
702+
}
703+
688704
/**
689705
* Sets the millisecond positions of extra ad markers relative to the start of the window (or
690706
* timeline, if in multi-window mode) and whether each extra ad has been played or not. The
@@ -992,7 +1008,7 @@ private void updatePlayPauseButton() {
9921008
return;
9931009
}
9941010
if (playPauseButton != null) {
995-
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
1011+
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player, showPlayButtonIfSuppressed);
9961012
@DrawableRes
9971013
int drawableRes =
9981014
shouldShowPlayButton
@@ -1491,7 +1507,7 @@ public boolean dispatchMediaKeyEvent(KeyEvent event) {
14911507
switch (keyCode) {
14921508
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
14931509
case KeyEvent.KEYCODE_HEADSETHOOK:
1494-
Util.handlePlayPauseButtonAction(player);
1510+
Util.handlePlayPauseButtonAction(player, showPlayButtonIfSuppressed);
14951511
break;
14961512
case KeyEvent.KEYCODE_MEDIA_PLAY:
14971513
Util.handlePlayButtonAction(player);
@@ -1722,7 +1738,7 @@ public void onClick(View view) {
17221738
player.seekBack();
17231739
}
17241740
} else if (playPauseButton == view) {
1725-
Util.handlePlayPauseButtonAction(player);
1741+
Util.handlePlayPauseButtonAction(player, showPlayButtonIfSuppressed);
17261742
} else if (repeatToggleButton == view) {
17271743
if (player.isCommandAvailable(COMMAND_SET_REPEAT_MODE)) {
17281744
player.setRepeatMode(

library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java

+14
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,20 @@ public void setShowMultiWindowTimeBar(boolean showMultiWindowTimeBar) {
10971097
controller.setShowMultiWindowTimeBar(showMultiWindowTimeBar);
10981098
}
10991099

1100+
/**
1101+
* Sets whether a play button is shown if playback is {@linkplain
1102+
* Player#getPlaybackSuppressionReason() suppressed}.
1103+
*
1104+
* <p>The default is {@code true}.
1105+
*
1106+
* @param showPlayButtonIfSuppressed Whether to show a play button if playback is {@linkplain
1107+
* Player#getPlaybackSuppressionReason() suppressed}.
1108+
*/
1109+
public void setShowPlayButtonIfPlaybackIsSuppressed(boolean showPlayButtonIfSuppressed) {
1110+
Assertions.checkStateNotNull(controller);
1111+
controller.setShowPlayButtonIfPlaybackIsSuppressed(showPlayButtonIfSuppressed);
1112+
}
1113+
11001114
/**
11011115
* Sets the millisecond positions of extra ad markers relative to the start of the window (or
11021116
* timeline, if in multi-window mode) and whether each extra ad has been played or not. The

0 commit comments

Comments
 (0)