mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Make play button behave differently in IDLE and ENDED states
- In IDLE, the button will now call a preparer. This allows removal of the separate retry button from the demo app. - In ENDED, the button will seek back to the default position and play. - Behavior is made consistent with LeanbackPlayerAdapter. Issue: #3689 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=182506855
This commit is contained in:
parent
7cacbfedc5
commit
4828f275c7
8 changed files with 94 additions and 27 deletions
|
|
@ -19,12 +19,15 @@
|
||||||
periods.
|
periods.
|
||||||
* Replaced `ExoPlayer.sendMessages` with `ExoPlayer.createMessage` to allow
|
* Replaced `ExoPlayer.sendMessages` with `ExoPlayer.createMessage` to allow
|
||||||
more customization of the message. Now supports setting a message delivery
|
more customization of the message. Now supports setting a message delivery
|
||||||
playback position and/or a delivery handler.
|
playback position and/or a delivery handler
|
||||||
([#2189](https://github.com/google/ExoPlayer/issues/2189)).
|
([#2189](https://github.com/google/ExoPlayer/issues/2189)).
|
||||||
* UI components:
|
* UI components:
|
||||||
* Generalized player and control views to allow them to bind with any
|
* Generalized player and control views to allow them to bind with any
|
||||||
`Player`, and renamed them to `PlayerView` and `PlayerControlView`
|
`Player`, and renamed them to `PlayerView` and `PlayerControlView`
|
||||||
respectively.
|
respectively.
|
||||||
|
* Made `PlayerView`'s play button behave correctly when the player is ended
|
||||||
|
([#3689](https://github.com/google/ExoPlayer/issues/3689)), and call a
|
||||||
|
`PlaybackPreparer` when the player is idle.
|
||||||
* Buffering:
|
* Buffering:
|
||||||
* Allow a back-buffer of media to be retained behind the current playback
|
* Allow a back-buffer of media to be retained behind the current playback
|
||||||
position, for fast backward seeking. The back-buffer can be configured by
|
position, for fast backward seeking. The back-buffer can be configured by
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import com.google.android.exoplayer2.C.ContentType;
|
||||||
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||||
|
import com.google.android.exoplayer2.PlaybackPreparer;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
||||||
|
|
@ -82,7 +83,7 @@ import java.util.UUID;
|
||||||
|
|
||||||
/** An activity that plays media using {@link SimpleExoPlayer}. */
|
/** An activity that plays media using {@link SimpleExoPlayer}. */
|
||||||
public class PlayerActivity extends Activity
|
public class PlayerActivity extends Activity
|
||||||
implements OnClickListener, PlayerControlView.VisibilityListener {
|
implements OnClickListener, PlaybackPreparer, PlayerControlView.VisibilityListener {
|
||||||
|
|
||||||
public static final String DRM_SCHEME_EXTRA = "drm_scheme";
|
public static final String DRM_SCHEME_EXTRA = "drm_scheme";
|
||||||
public static final String DRM_LICENSE_URL = "drm_license_url";
|
public static final String DRM_LICENSE_URL = "drm_license_url";
|
||||||
|
|
@ -114,7 +115,6 @@ public class PlayerActivity extends Activity
|
||||||
private PlayerView playerView;
|
private PlayerView playerView;
|
||||||
private LinearLayout debugRootView;
|
private LinearLayout debugRootView;
|
||||||
private TextView debugTextView;
|
private TextView debugTextView;
|
||||||
private Button retryButton;
|
|
||||||
|
|
||||||
private DataSource.Factory mediaDataSourceFactory;
|
private DataSource.Factory mediaDataSourceFactory;
|
||||||
private SimpleExoPlayer player;
|
private SimpleExoPlayer player;
|
||||||
|
|
@ -152,8 +152,6 @@ public class PlayerActivity extends Activity
|
||||||
rootView.setOnClickListener(this);
|
rootView.setOnClickListener(this);
|
||||||
debugRootView = findViewById(R.id.controls_root);
|
debugRootView = findViewById(R.id.controls_root);
|
||||||
debugTextView = findViewById(R.id.debug_text_view);
|
debugTextView = findViewById(R.id.debug_text_view);
|
||||||
retryButton = findViewById(R.id.retry_button);
|
|
||||||
retryButton.setOnClickListener(this);
|
|
||||||
|
|
||||||
playerView = findViewById(R.id.player_view);
|
playerView = findViewById(R.id.player_view);
|
||||||
playerView.setControllerVisibilityListener(this);
|
playerView.setControllerVisibilityListener(this);
|
||||||
|
|
@ -229,9 +227,7 @@ public class PlayerActivity extends Activity
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if (view == retryButton) {
|
if (view.getParent() == debugRootView) {
|
||||||
initializePlayer();
|
|
||||||
} else if (view.getParent() == debugRootView) {
|
|
||||||
MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
|
MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
|
||||||
if (mappedTrackInfo != null) {
|
if (mappedTrackInfo != null) {
|
||||||
trackSelectionHelper.showSelectionDialog(
|
trackSelectionHelper.showSelectionDialog(
|
||||||
|
|
@ -240,6 +236,13 @@ public class PlayerActivity extends Activity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PlaybackControlView.PlaybackPreparer implementation
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preparePlayback() {
|
||||||
|
initializePlayer();
|
||||||
|
}
|
||||||
|
|
||||||
// PlaybackControlView.VisibilityListener implementation
|
// PlaybackControlView.VisibilityListener implementation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -301,9 +304,10 @@ public class PlayerActivity extends Activity
|
||||||
player.addMetadataOutput(eventLogger);
|
player.addMetadataOutput(eventLogger);
|
||||||
player.addAudioDebugListener(eventLogger);
|
player.addAudioDebugListener(eventLogger);
|
||||||
player.addVideoDebugListener(eventLogger);
|
player.addVideoDebugListener(eventLogger);
|
||||||
|
player.setPlayWhenReady(shouldAutoPlay);
|
||||||
|
|
||||||
playerView.setPlayer(player);
|
playerView.setPlayer(player);
|
||||||
player.setPlayWhenReady(shouldAutoPlay);
|
playerView.setPlaybackPreparer(this);
|
||||||
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
||||||
debugViewHelper.start();
|
debugViewHelper.start();
|
||||||
}
|
}
|
||||||
|
|
@ -502,10 +506,6 @@ public class PlayerActivity extends Activity
|
||||||
|
|
||||||
private void updateButtonVisibilities() {
|
private void updateButtonVisibilities() {
|
||||||
debugRootView.removeAllViews();
|
debugRootView.removeAllViews();
|
||||||
|
|
||||||
retryButton.setVisibility(inErrorState ? View.VISIBLE : View.GONE);
|
|
||||||
debugRootView.addView(retryButton);
|
|
||||||
|
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,16 +42,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<Button android:id="@+id/retry_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/retry"
|
|
||||||
android:visibility="gone"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
|
|
||||||
<string name="text">Text</string>
|
<string name="text">Text</string>
|
||||||
|
|
||||||
<string name="retry">Retry</string>
|
|
||||||
|
|
||||||
<string name="selection_disabled">Disabled</string>
|
<string name="selection_disabled">Disabled</string>
|
||||||
|
|
||||||
<string name="selection_default">Default</string>
|
<string name="selection_default">Default</string>
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import com.google.android.exoplayer2.ControlDispatcher;
|
||||||
import com.google.android.exoplayer2.DefaultControlDispatcher;
|
import com.google.android.exoplayer2.DefaultControlDispatcher;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||||
|
import com.google.android.exoplayer2.PlaybackPreparer;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
||||||
import com.google.android.exoplayer2.Player.TimelineChangeReason;
|
import com.google.android.exoplayer2.Player.TimelineChangeReason;
|
||||||
|
|
@ -50,6 +51,7 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
||||||
private final ComponentListener componentListener;
|
private final ComponentListener componentListener;
|
||||||
private final Runnable updateProgressRunnable;
|
private final Runnable updateProgressRunnable;
|
||||||
|
|
||||||
|
private @Nullable PlaybackPreparer playbackPreparer;
|
||||||
private ControlDispatcher controlDispatcher;
|
private ControlDispatcher controlDispatcher;
|
||||||
private ErrorMessageProvider<? super ExoPlaybackException> errorMessageProvider;
|
private ErrorMessageProvider<? super ExoPlaybackException> errorMessageProvider;
|
||||||
private SurfaceHolderGlueHost surfaceHolderGlueHost;
|
private SurfaceHolderGlueHost surfaceHolderGlueHost;
|
||||||
|
|
@ -82,6 +84,15 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link PlaybackPreparer}.
|
||||||
|
*
|
||||||
|
* @param playbackPreparer The {@link PlaybackPreparer}.
|
||||||
|
*/
|
||||||
|
public void setPlaybackPreparer(@Nullable PlaybackPreparer playbackPreparer) {
|
||||||
|
this.playbackPreparer = playbackPreparer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link ControlDispatcher}.
|
* Sets the {@link ControlDispatcher}.
|
||||||
*
|
*
|
||||||
|
|
@ -165,7 +176,11 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void play() {
|
public void play() {
|
||||||
if (player.getPlaybackState() == Player.STATE_ENDED) {
|
if (player.getPlaybackState() == Player.STATE_IDLE) {
|
||||||
|
if (playbackPreparer != null) {
|
||||||
|
playbackPreparer.preparePlayback();
|
||||||
|
}
|
||||||
|
} else if (player.getPlaybackState() == Player.STATE_ENDED) {
|
||||||
controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
|
controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
if (controlDispatcher.dispatchSetPlayWhenReady(player, true)) {
|
if (controlDispatcher.dispatchSetPlayWhenReady(player, true)) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2;
|
||||||
|
|
||||||
|
/** Called to prepare a playback. */
|
||||||
|
public interface PlaybackPreparer {
|
||||||
|
|
||||||
|
/** Called to prepare a playback. */
|
||||||
|
void preparePlayback();
|
||||||
|
}
|
||||||
|
|
@ -31,6 +31,7 @@ import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||||
|
import com.google.android.exoplayer2.PlaybackPreparer;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
|
@ -217,6 +218,7 @@ public class PlayerControlView extends FrameLayout {
|
||||||
private Player player;
|
private Player player;
|
||||||
private com.google.android.exoplayer2.ControlDispatcher controlDispatcher;
|
private com.google.android.exoplayer2.ControlDispatcher controlDispatcher;
|
||||||
private VisibilityListener visibilityListener;
|
private VisibilityListener visibilityListener;
|
||||||
|
private @Nullable PlaybackPreparer playbackPreparer;
|
||||||
|
|
||||||
private boolean isAttachedToWindow;
|
private boolean isAttachedToWindow;
|
||||||
private boolean showMultiWindowTimeBar;
|
private boolean showMultiWindowTimeBar;
|
||||||
|
|
@ -431,6 +433,15 @@ public class PlayerControlView extends FrameLayout {
|
||||||
this.visibilityListener = listener;
|
this.visibilityListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link PlaybackPreparer}.
|
||||||
|
*
|
||||||
|
* @param playbackPreparer The {@link PlaybackPreparer}.
|
||||||
|
*/
|
||||||
|
public void setPlaybackPreparer(@Nullable PlaybackPreparer playbackPreparer) {
|
||||||
|
this.playbackPreparer = playbackPreparer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link com.google.android.exoplayer2.ControlDispatcher}.
|
* Sets the {@link com.google.android.exoplayer2.ControlDispatcher}.
|
||||||
*
|
*
|
||||||
|
|
@ -599,7 +610,7 @@ public class PlayerControlView extends FrameLayout {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean requestPlayPauseFocus = false;
|
boolean requestPlayPauseFocus = false;
|
||||||
boolean playing = player != null && player.getPlayWhenReady();
|
boolean playing = isPlaying();
|
||||||
if (playButton != null) {
|
if (playButton != null) {
|
||||||
requestPlayPauseFocus |= playing && playButton.isFocused();
|
requestPlayPauseFocus |= playing && playButton.isFocused();
|
||||||
playButton.setVisibility(playing ? View.GONE : View.VISIBLE);
|
playButton.setVisibility(playing ? View.GONE : View.VISIBLE);
|
||||||
|
|
@ -811,7 +822,7 @@ public class PlayerControlView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requestPlayPauseFocus() {
|
private void requestPlayPauseFocus() {
|
||||||
boolean playing = player != null && player.getPlayWhenReady();
|
boolean playing = isPlaying();
|
||||||
if (!playing && playButton != null) {
|
if (!playing && playButton != null) {
|
||||||
playButton.requestFocus();
|
playButton.requestFocus();
|
||||||
} else if (playing && pauseButton != null) {
|
} else if (playing && pauseButton != null) {
|
||||||
|
|
@ -985,6 +996,13 @@ public class PlayerControlView extends FrameLayout {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isPlaying() {
|
||||||
|
return player != null
|
||||||
|
&& player.getPlaybackState() != Player.STATE_ENDED
|
||||||
|
&& player.getPlaybackState() != Player.STATE_IDLE
|
||||||
|
&& player.getPlayWhenReady();
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
private static boolean isHandledMediaKey(int keyCode) {
|
private static boolean isHandledMediaKey(int keyCode) {
|
||||||
return keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
|
return keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
|
||||||
|
|
@ -1085,6 +1103,13 @@ public class PlayerControlView extends FrameLayout {
|
||||||
} else if (rewindButton == view) {
|
} else if (rewindButton == view) {
|
||||||
rewind();
|
rewind();
|
||||||
} else if (playButton == view) {
|
} else if (playButton == view) {
|
||||||
|
if (player.getPlaybackState() == Player.STATE_IDLE) {
|
||||||
|
if (playbackPreparer != null) {
|
||||||
|
playbackPreparer.preparePlayback();
|
||||||
|
}
|
||||||
|
} else if (player.getPlaybackState() == Player.STATE_ENDED) {
|
||||||
|
controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
|
||||||
|
}
|
||||||
controlDispatcher.dispatchSetPlayWhenReady(player, true);
|
controlDispatcher.dispatchSetPlayWhenReady(player, true);
|
||||||
} else if (pauseButton == view) {
|
} else if (pauseButton == view) {
|
||||||
controlDispatcher.dispatchSetPlayWhenReady(player, false);
|
controlDispatcher.dispatchSetPlayWhenReady(player, false);
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import android.widget.ImageView;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ControlDispatcher;
|
import com.google.android.exoplayer2.ControlDispatcher;
|
||||||
import com.google.android.exoplayer2.DefaultControlDispatcher;
|
import com.google.android.exoplayer2.DefaultControlDispatcher;
|
||||||
|
import com.google.android.exoplayer2.PlaybackPreparer;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
|
|
@ -676,6 +677,16 @@ public class PlayerView extends FrameLayout {
|
||||||
controller.setVisibilityListener(listener);
|
controller.setVisibilityListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link PlaybackPreparer}.
|
||||||
|
*
|
||||||
|
* @param playbackPreparer The {@link PlaybackPreparer}.
|
||||||
|
*/
|
||||||
|
public void setPlaybackPreparer(@Nullable PlaybackPreparer playbackPreparer) {
|
||||||
|
Assertions.checkState(controller != null);
|
||||||
|
controller.setPlaybackPreparer(playbackPreparer);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link ControlDispatcher}.
|
* Sets the {@link ControlDispatcher}.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue