Commit ab30715a by tonihei Committed by Ian Baker

Use Util method for common UI play/pause button logic.

This ensures the logic is consistent and can also be easily
used from custom UIs.

PiperOrigin-RevId: 527249127
parent 51228fc7
......@@ -119,10 +119,7 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter implements Runnab
@Override
public boolean isPlaying() {
int playbackState = player.getPlaybackState();
return playbackState != Player.STATE_IDLE
&& playbackState != Player.STATE_ENDED
&& player.getPlayWhenReady();
return !Util.shouldShowPlayButton(player);
}
@Override
......@@ -140,13 +137,7 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter implements Runnab
@SuppressWarnings("nullness:dereference.of.nullable")
@Override
public void play() {
if (player.getPlaybackState() == Player.STATE_IDLE) {
player.prepare();
} else if (player.getPlaybackState() == Player.STATE_ENDED) {
player.seekToDefaultPosition(player.getCurrentMediaItemIndex());
}
if (player.isCommandAvailable(Player.COMMAND_PLAY_PAUSE)) {
player.play();
if (Util.handlePlayButtonAction(player)) {
getCallback().onPlayStateChanged(this);
}
}
......@@ -155,8 +146,7 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter implements Runnab
@SuppressWarnings("nullness:dereference.of.nullable")
@Override
public void pause() {
if (player.isCommandAvailable(Player.COMMAND_PLAY_PAUSE)) {
player.pause();
if (Util.handlePauseButtonAction(player)) {
getCallback().onPlayStateChanged(this);
}
}
......
......@@ -165,7 +165,7 @@ public class SessionPlayerConnectorTest {
new ForwardingPlayer(exoPlayer) {
@Override
public boolean isCommandAvailable(int command) {
if (command == COMMAND_PLAY_PAUSE) {
if (command == COMMAND_PLAY_PAUSE || command == COMMAND_PREPARE) {
return false;
}
return super.isCommandAvailable(command);
......@@ -173,7 +173,10 @@ public class SessionPlayerConnectorTest {
@Override
public Commands getAvailableCommands() {
return super.getAvailableCommands().buildUpon().remove(COMMAND_PLAY_PAUSE).build();
return super.getAvailableCommands()
.buildUpon()
.removeAll(COMMAND_PLAY_PAUSE, COMMAND_PREPARE)
.build();
}
};
playerConnector = new SessionPlayerConnector(forwardingPlayer);
......
......@@ -16,7 +16,6 @@
package com.google.android.exoplayer2.ext.media2;
import static com.google.android.exoplayer2.Player.COMMAND_GET_AUDIO_ATTRIBUTES;
import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT;
......@@ -327,31 +326,17 @@ import java.util.List;
}
public boolean play() {
if (player.getPlaybackState() == Player.STATE_ENDED) {
if (!player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)) {
return false;
}
player.seekTo(player.getCurrentMediaItemIndex(), /* positionMs= */ 0);
if (!player.getPlayWhenReady()) {
return Util.handlePlayButtonAction(player);
}
boolean playWhenReady = player.getPlayWhenReady();
int suppressReason = player.getPlaybackSuppressionReason();
if ((playWhenReady && suppressReason == Player.PLAYBACK_SUPPRESSION_REASON_NONE)
|| !player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
return false;
}
player.play();
return true;
return false;
}
public boolean pause() {
boolean playWhenReady = player.getPlayWhenReady();
int suppressReason = player.getPlaybackSuppressionReason();
if ((!playWhenReady && suppressReason == Player.PLAYBACK_SUPPRESSION_REASON_NONE)
|| !player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
return false;
if (player.getPlayWhenReady()) {
return Util.handlePauseButtonAction(player);
}
player.pause();
return true;
return false;
}
public boolean seekTo(long position) {
......
......@@ -17,6 +17,8 @@ package com.google.android.exoplayer2.util;
import static android.content.Context.UI_MODE_SERVICE;
import static com.google.android.exoplayer2.C.UNLIMITED_PENDING_FRAME_COUNT;
import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE;
import static com.google.android.exoplayer2.Player.COMMAND_PREPARE;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_BACK;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_FORWARD;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
......@@ -123,6 +125,7 @@ import java.util.zip.Inflater;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.PolyNull;
/** Miscellaneous utility methods. */
......@@ -2810,6 +2813,87 @@ public final class Util {
return Integer.toString(i, Character.MAX_RADIX);
}
/**
* Returns whether a play button should be presented on a UI element for playback control. If
* {@code false}, a pause button should be shown instead.
*
* <p>Use {@link #handlePlayPauseButtonAction}, {@link #handlePlayButtonAction} or {@link
* #handlePauseButtonAction} to handle the interaction with the play or pause button UI element.
*
* @param player The {@link Player}. May be null.
*/
@EnsuresNonNullIf(result = false, expression = "#1")
public static boolean shouldShowPlayButton(@Nullable Player player) {
return player == null
|| !player.getPlayWhenReady()
|| player.getPlaybackState() == Player.STATE_IDLE
|| player.getPlaybackState() == Player.STATE_ENDED;
}
/**
* Updates the player to handle an interaction with a play button.
*
* <p>This method assumes the play button is enabled if {@link #shouldShowPlayButton} returns
* true.
*
* @param player The {@link Player}. May be null.
* @return Whether a player method was triggered to handle this action.
*/
public static boolean handlePlayButtonAction(@Nullable Player player) {
if (player == null) {
return false;
}
@Player.State int state = player.getPlaybackState();
boolean methodTriggered = false;
if (state == Player.STATE_IDLE && player.isCommandAvailable(COMMAND_PREPARE)) {
player.prepare();
methodTriggered = true;
} else if (state == Player.STATE_ENDED
&& player.isCommandAvailable(COMMAND_SEEK_TO_DEFAULT_POSITION)) {
player.seekToDefaultPosition();
methodTriggered = true;
}
if (player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.play();
methodTriggered = true;
}
return methodTriggered;
}
/**
* Updates the player to handle an interaction with a pause button.
*
* <p>This method assumes the pause button is enabled if {@link #shouldShowPlayButton} returns
* false.
*
* @param player The {@link Player}. May be null.
* @return Whether a player method was triggered to handle this action.
*/
public static boolean handlePauseButtonAction(@Nullable Player player) {
if (player != null && player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.pause();
return true;
}
return false;
}
/**
* Updates the player to handle an interaction with a play or pause button.
*
* <p>This method assumes that the UI element enables a play button if {@link
* #shouldShowPlayButton} returns true and a pause button otherwise.
*
* @param player The {@link Player}. May be null.
* @return Whether a player method was triggered to handle this action.
*/
public static boolean handlePlayPauseButtonAction(@Nullable Player player) {
if (shouldShowPlayButton(player)) {
return handlePlayButtonAction(player);
} else {
return handlePauseButtonAction(player);
}
}
@Nullable
private static String getSystemProperty(String name) {
try {
......
......@@ -54,7 +54,6 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.Events;
import com.google.android.exoplayer2.Player.State;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.RepeatModeUtil;
......@@ -825,22 +824,22 @@ public class PlayerControlView extends FrameLayout {
}
boolean requestPlayPauseFocus = false;
boolean requestPlayPauseAccessibilityFocus = false;
boolean shouldShowPauseButton = shouldShowPauseButton();
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
if (playButton != null) {
requestPlayPauseFocus |= shouldShowPauseButton && playButton.isFocused();
requestPlayPauseFocus |= !shouldShowPlayButton && playButton.isFocused();
requestPlayPauseAccessibilityFocus |=
Util.SDK_INT < 21
? requestPlayPauseFocus
: (shouldShowPauseButton && Api21.isAccessibilityFocused(playButton));
playButton.setVisibility(shouldShowPauseButton ? GONE : VISIBLE);
: (!shouldShowPlayButton && Api21.isAccessibilityFocused(playButton));
playButton.setVisibility(shouldShowPlayButton ? VISIBLE : GONE);
}
if (pauseButton != null) {
requestPlayPauseFocus |= !shouldShowPauseButton && pauseButton.isFocused();
requestPlayPauseFocus |= shouldShowPlayButton && pauseButton.isFocused();
requestPlayPauseAccessibilityFocus |=
Util.SDK_INT < 21
? requestPlayPauseFocus
: (!shouldShowPauseButton && Api21.isAccessibilityFocused(pauseButton));
pauseButton.setVisibility(shouldShowPauseButton ? VISIBLE : GONE);
: (shouldShowPlayButton && Api21.isAccessibilityFocused(pauseButton));
pauseButton.setVisibility(shouldShowPlayButton ? GONE : VISIBLE);
}
if (requestPlayPauseFocus) {
requestPlayPauseFocus();
......@@ -1066,19 +1065,19 @@ public class PlayerControlView extends FrameLayout {
}
private void requestPlayPauseFocus() {
boolean shouldShowPauseButton = shouldShowPauseButton();
if (!shouldShowPauseButton && playButton != null) {
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
if (shouldShowPlayButton && playButton != null) {
playButton.requestFocus();
} else if (shouldShowPauseButton && pauseButton != null) {
} else if (!shouldShowPlayButton && pauseButton != null) {
pauseButton.requestFocus();
}
}
private void requestPlayPauseAccessibilityFocus() {
boolean shouldShowPauseButton = shouldShowPauseButton();
if (!shouldShowPauseButton && playButton != null) {
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
if (shouldShowPlayButton && playButton != null) {
playButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
} else if (shouldShowPauseButton && pauseButton != null) {
} else if (!shouldShowPlayButton && pauseButton != null) {
pauseButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
}
......@@ -1185,13 +1184,13 @@ public class PlayerControlView extends FrameLayout {
switch (keyCode) {
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
case KeyEvent.KEYCODE_HEADSETHOOK:
dispatchPlayPause(player);
Util.handlePlayPauseButtonAction(player);
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
dispatchPlay(player);
Util.handlePlayButtonAction(player);
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
dispatchPause(player);
Util.handlePauseButtonAction(player);
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
player.seekToNext();
......@@ -1207,36 +1206,6 @@ public class PlayerControlView extends FrameLayout {
return true;
}
private boolean shouldShowPauseButton() {
return player != null
&& player.getPlaybackState() != Player.STATE_ENDED
&& player.getPlaybackState() != Player.STATE_IDLE
&& player.getPlayWhenReady();
}
private void dispatchPlayPause(Player player) {
@State int state = player.getPlaybackState();
if (state == Player.STATE_IDLE || state == Player.STATE_ENDED || !player.getPlayWhenReady()) {
dispatchPlay(player);
} else {
dispatchPause(player);
}
}
private void dispatchPlay(Player player) {
@State int state = player.getPlaybackState();
if (state == Player.STATE_IDLE) {
player.prepare();
} else if (state == Player.STATE_ENDED) {
seekTo(player, player.getCurrentMediaItemIndex(), C.TIME_UNSET);
}
player.play();
}
private void dispatchPause(Player player) {
player.pause();
}
@SuppressLint("InlinedApi")
private static boolean isHandledMediaKey(int keyCode) {
return keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
......@@ -1346,9 +1315,9 @@ public class PlayerControlView extends FrameLayout {
} else if (rewindButton == view) {
player.seekBack();
} else if (playButton == view) {
dispatchPlay(player);
Util.handlePlayButtonAction(player);
} else if (pauseButton == view) {
dispatchPause(player);
Util.handlePauseButtonAction(player);
} else if (repeatToggleButton == view) {
player.setRepeatMode(
RepeatModeUtil.getNextRepeatMode(player.getRepeatMode(), repeatToggleModes));
......
......@@ -18,11 +18,8 @@ package com.google.android.exoplayer2.ui;
import static com.google.android.exoplayer2.Player.COMMAND_CHANGE_MEDIA_ITEMS;
import static com.google.android.exoplayer2.Player.COMMAND_GET_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_GET_TIMELINE;
import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE;
import static com.google.android.exoplayer2.Player.COMMAND_PREPARE;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_BACK;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_FORWARD;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_DEFAULT_POSITION;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS;
import static com.google.android.exoplayer2.Player.COMMAND_STOP;
......@@ -1332,10 +1329,10 @@ public class PlayerNotificationManager {
stringActions.add(ACTION_REWIND);
}
if (usePlayPauseActions) {
if (shouldShowPauseButton(player)) {
stringActions.add(ACTION_PAUSE);
} else {
if (Util.shouldShowPlayButton(player)) {
stringActions.add(ACTION_PLAY);
} else {
stringActions.add(ACTION_PAUSE);
}
}
if (useFastForwardAction && enableFastForward) {
......@@ -1380,10 +1377,10 @@ public class PlayerNotificationManager {
if (leftSideActionIndex != -1) {
actionIndices[actionCounter++] = leftSideActionIndex;
}
boolean shouldShowPauseButton = shouldShowPauseButton(player);
if (pauseActionIndex != -1 && shouldShowPauseButton) {
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
if (pauseActionIndex != -1 && !shouldShowPlayButton) {
actionIndices[actionCounter++] = pauseActionIndex;
} else if (playActionIndex != -1 && !shouldShowPauseButton) {
} else if (playActionIndex != -1 && shouldShowPlayButton) {
actionIndices[actionCounter++] = playActionIndex;
}
if (rightSideActionIndex != -1) {
......@@ -1399,12 +1396,6 @@ public class PlayerNotificationManager {
&& player.getPlayWhenReady();
}
private boolean shouldShowPauseButton(Player player) {
return player.getPlaybackState() != Player.STATE_ENDED
&& player.getPlaybackState() != Player.STATE_IDLE
&& player.getPlayWhenReady();
}
private void postStartOrUpdateNotification() {
if (!mainHandler.hasMessages(MSG_START_OR_UPDATE_NOTIFICATION)) {
mainHandler.sendEmptyMessage(MSG_START_OR_UPDATE_NOTIFICATION);
......@@ -1545,20 +1536,9 @@ public class PlayerNotificationManager {
}
String action = intent.getAction();
if (ACTION_PLAY.equals(action)) {
if (player.getPlaybackState() == Player.STATE_IDLE
&& player.isCommandAvailable(COMMAND_PREPARE)) {
player.prepare();
} else if (player.getPlaybackState() == Player.STATE_ENDED
&& player.isCommandAvailable(COMMAND_SEEK_TO_DEFAULT_POSITION)) {
player.seekToDefaultPosition();
}
if (player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.play();
}
Util.handlePlayButtonAction(player);
} else if (ACTION_PAUSE.equals(action)) {
if (player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.pause();
}
Util.handlePauseButtonAction(player);
} else if (ACTION_PREVIOUS.equals(action)) {
if (player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS)) {
player.seekToPrevious();
......
......@@ -19,11 +19,9 @@ import static com.google.android.exoplayer2.Player.COMMAND_GET_CURRENT_MEDIA_ITE
import static com.google.android.exoplayer2.Player.COMMAND_GET_TIMELINE;
import static com.google.android.exoplayer2.Player.COMMAND_GET_TRACKS;
import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE;
import static com.google.android.exoplayer2.Player.COMMAND_PREPARE;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_BACK;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_FORWARD;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_DEFAULT_POSITION;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS;
......@@ -77,7 +75,6 @@ import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.Events;
import com.google.android.exoplayer2.Player.State;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.source.TrackGroup;
......@@ -984,17 +981,17 @@ public class StyledPlayerControlView extends FrameLayout {
return;
}
if (playPauseButton != null) {
boolean shouldShowPauseButton = shouldShowPauseButton();
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
@DrawableRes
int drawableRes =
shouldShowPauseButton
? R.drawable.exo_styled_controls_pause
: R.drawable.exo_styled_controls_play;
shouldShowPlayButton
? R.drawable.exo_styled_controls_play
: R.drawable.exo_styled_controls_pause;
@StringRes
int stringRes =
shouldShowPauseButton
? R.string.exo_controls_pause_description
: R.string.exo_controls_play_description;
shouldShowPlayButton
? R.string.exo_controls_play_description
: R.string.exo_controls_pause_description;
((ImageView) playPauseButton)
.setImageDrawable(getDrawable(getContext(), resources, drawableRes));
playPauseButton.setContentDescription(resources.getString(stringRes));
......@@ -1483,13 +1480,13 @@ public class StyledPlayerControlView extends FrameLayout {
switch (keyCode) {
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
case KeyEvent.KEYCODE_HEADSETHOOK:
dispatchPlayPause(player);
Util.handlePlayPauseButtonAction(player);
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
dispatchPlay(player);
Util.handlePlayButtonAction(player);
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
dispatchPause(player);
Util.handlePauseButtonAction(player);
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
if (player.isCommandAvailable(COMMAND_SEEK_TO_NEXT)) {
......@@ -1545,41 +1542,6 @@ public class StyledPlayerControlView extends FrameLayout {
|| !player.getCurrentTimeline().isEmpty());
}
private boolean shouldShowPauseButton() {
return player != null
&& player.getPlaybackState() != Player.STATE_ENDED
&& player.getPlaybackState() != Player.STATE_IDLE
&& player.getPlayWhenReady();
}
private void dispatchPlayPause(Player player) {
@State int state = player.getPlaybackState();
if (state == Player.STATE_IDLE || state == Player.STATE_ENDED || !player.getPlayWhenReady()) {
dispatchPlay(player);
} else {
dispatchPause(player);
}
}
private void dispatchPlay(Player player) {
@State int state = player.getPlaybackState();
if (state == Player.STATE_IDLE && player.isCommandAvailable(COMMAND_PREPARE)) {
player.prepare();
} else if (state == Player.STATE_ENDED
&& player.isCommandAvailable(COMMAND_SEEK_TO_DEFAULT_POSITION)) {
player.seekToDefaultPosition();
}
if (player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.play();
}
}
private void dispatchPause(Player player) {
if (player.isCommandAvailable(COMMAND_PLAY_PAUSE)) {
player.pause();
}
}
@SuppressLint("InlinedApi")
private static boolean isHandledMediaKey(int keyCode) {
return keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
......@@ -1749,7 +1711,7 @@ public class StyledPlayerControlView extends FrameLayout {
player.seekBack();
}
} else if (playPauseButton == view) {
dispatchPlayPause(player);
Util.handlePlayPauseButtonAction(player);
} else if (repeatToggleButton == view) {
if (player.isCommandAvailable(COMMAND_SET_REPEAT_MODE)) {
player.setRepeatMode(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment