diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c8efd4c1f53..9b070b0fa0b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -29,6 +29,13 @@ * UI: * Show overflow button in `StyledPlayerControlView` only when there is not enough space. + * Add `dispatchPrepare(Player)` to `ControlDispatcher` and implement it in + `DefaultControlDispatcher`. Deprecate `PlaybackPreparer` and + `setPlaybackPreparer` in `StyledPlayerView`, `StyledPlayerControlView`, + `PlayerView`, `PlayerControlView`, `PlayerNotificationManager` and + `LeanbackPlayerAdapter` and use `ControlDispatcher` for dispatching + prepare instead + ([#7882](https://github.com/google/ExoPlayer/issues/7882)). * Audio: * Retry playback after some types of `AudioTrack` error. * Extractors: diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 776ab68a799..78dd6e11a8b 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -34,7 +34,6 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.MediaItem; -import com.google.android.exoplayer2.PlaybackPreparer; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.SimpleExoPlayer; @@ -68,7 +67,7 @@ /** An activity that plays media using {@link SimpleExoPlayer}. */ public class PlayerActivity extends AppCompatActivity - implements OnClickListener, PlaybackPreparer, StyledPlayerControlView.VisibilityListener { + implements OnClickListener, StyledPlayerControlView.VisibilityListener { // Saved instance state keys. @@ -250,13 +249,6 @@ public void onClick(View view) { } } - // PlaybackPreparer implementation - - @Override - public void preparePlayback() { - player.prepare(); - } - // PlayerControlView.VisibilityListener implementation @Override @@ -302,7 +294,6 @@ protected boolean initializePlayer() { player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true); player.setPlayWhenReady(startAutoPlay); playerView.setPlayer(player); - playerView.setPlaybackPreparer(this); debugViewHelper = new DebugTextViewHelper(player, debugTextView); debugViewHelper.start(); } diff --git a/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java b/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java index 6538160b8b9..6da02bb3242 100644 --- a/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java +++ b/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java @@ -78,10 +78,15 @@ public LeanbackPlayerAdapter(Context context, Player player, final int updatePer } /** - * Sets the {@link PlaybackPreparer}. - * - * @param playbackPreparer The {@link PlaybackPreparer}. + * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} instead. The adapter calls + * {@link ControlDispatcher#dispatchPrepare(Player)} instead of {@link + * PlaybackPreparer#preparePlayback()}. The {@link DefaultControlDispatcher} that the adapter + * uses by default, calls {@link Player#prepare()}. If you wish to customize this behaviour, + * you can provide a custom implementation of {@link + * ControlDispatcher#dispatchPrepare(Player)}. */ + @SuppressWarnings("deprecation") + @Deprecated public void setPlaybackPreparer(@Nullable PlaybackPreparer playbackPreparer) { this.playbackPreparer = playbackPreparer; } @@ -167,11 +172,15 @@ public long getCurrentPosition() { return player.getPlaybackState() == Player.STATE_IDLE ? -1 : player.getCurrentPosition(); } + // Calls deprecated method to provide backwards compatibility. + @SuppressWarnings("deprecation") @Override public void play() { if (player.getPlaybackState() == Player.STATE_IDLE) { if (playbackPreparer != null) { playbackPreparer.preparePlayback(); + } else { + controlDispatcher.dispatchPrepare(player); } } else if (player.getPlaybackState() == Player.STATE_ENDED) { controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET); diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index 85d0155bd77..e78c55b2afb 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -1147,6 +1147,8 @@ public void onPlay() { if (player.getPlaybackState() == Player.STATE_IDLE) { if (playbackPreparer != null) { playbackPreparer.onPrepare(/* playWhenReady= */ true); + } else { + controlDispatcher.dispatchPrepare(player); } } else if (player.getPlaybackState() == Player.STATE_ENDED) { seekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java b/library/core/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java index 7b78147e129..0d5e55fc833 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java @@ -26,6 +26,14 @@ */ public interface ControlDispatcher { + /** + * Dispatches a {@link Player#prepare()} operation. + * + * @param player The {@link Player} to which the operation should be dispatched. + * @return True if the operation was dispatched. False if suppressed. + */ + boolean dispatchPrepare(Player player); + /** * Dispatches a {@link Player#setPlayWhenReady(boolean)} operation. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java index d46b939c1fc..25c468330c9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java @@ -52,6 +52,12 @@ public DefaultControlDispatcher(long fastForwardIncrementMs, long rewindIncremen window = new Timeline.Window(); } + @Override + public boolean dispatchPrepare(Player player) { + player.prepare(); + return true; + } + @Override public boolean dispatchSetPlayWhenReady(Player player, boolean playWhenReady) { player.setPlayWhenReady(playWhenReady); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackPreparer.java b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackPreparer.java index 8ff7f504025..3ef38c8520a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/PlaybackPreparer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/PlaybackPreparer.java @@ -15,9 +15,11 @@ */ package com.google.android.exoplayer2; -/** Called to prepare a playback. */ +/** @deprecated Use {@link ControlDispatcher} instead. */ +@Deprecated public interface PlaybackPreparer { - /** Called to prepare a playback. */ + /** @deprecated Use {@link ControlDispatcher#dispatchPrepare(Player)} instead. */ + @Deprecated void preparePlayback(); } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java index 65a9a5ed8f7..1ae7812bd46 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java @@ -611,11 +611,15 @@ public void setProgressUpdateListener(@Nullable ProgressUpdateListener listener) } /** - * Sets the {@link PlaybackPreparer}. - * - * @param playbackPreparer The {@link PlaybackPreparer}, or null to remove the current playback - * preparer. + * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} instead. The view calls {@link + * ControlDispatcher#dispatchPrepare(Player)} instead of {@link + * PlaybackPreparer#preparePlayback()}. The {@link DefaultControlDispatcher} that the view + * uses by default, calls {@link Player#prepare()}. If you wish to customize this behaviour, + * you can provide a custom implementation of {@link + * ControlDispatcher#dispatchPrepare(Player)}. */ + @SuppressWarnings("deprecation") + @Deprecated public void setPlaybackPreparer(@Nullable PlaybackPreparer playbackPreparer) { this.playbackPreparer = playbackPreparer; } @@ -1254,11 +1258,14 @@ private void dispatchPlayPause(Player player) { } } + @SuppressWarnings("deprecation") private void dispatchPlay(Player player) { @State int state = player.getPlaybackState(); if (state == Player.STATE_IDLE) { if (playbackPreparer != null) { playbackPreparer.preparePlayback(); + } else { + controlDispatcher.dispatchPrepare(player); } } else if (state == Player.STATE_ENDED) { seekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java index 7c899c1ea21..b183fddbb6c 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java @@ -682,10 +682,16 @@ public final void setPlayer(@Nullable Player player) { } /** - * Sets the {@link PlaybackPreparer}. - * - * @param playbackPreparer The {@link PlaybackPreparer}. + * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} instead. The manager calls + * {@link ControlDispatcher#dispatchPrepare(Player)} instead of {@link + * PlaybackPreparer#preparePlayback()}. The {@link DefaultControlDispatcher} that this manager + * uses by default, calls {@link Player#prepare()}. If you wish to intercept or customize this + * behaviour, you can provide a custom implementation of {@link + * ControlDispatcher#dispatchPrepare(Player)} and pass it to {@link + * #setControlDispatcher(ControlDispatcher)}. */ + @SuppressWarnings("deprecation") + @Deprecated public void setPlaybackPreparer(@Nullable PlaybackPreparer playbackPreparer) { this.playbackPreparer = playbackPreparer; } @@ -1039,8 +1045,7 @@ protected NotificationCompat.Builder createNotification( @Nullable NotificationCompat.Builder builder, boolean ongoing, @Nullable Bitmap largeIcon) { - if (player.getPlaybackState() == Player.STATE_IDLE - && (player.getCurrentTimeline().isEmpty() || playbackPreparer == null)) { + if (player.getPlaybackState() == Player.STATE_IDLE && player.getCurrentTimeline().isEmpty()) { builderActions = null; return null; } @@ -1369,6 +1374,7 @@ public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) { private class NotificationBroadcastReceiver extends BroadcastReceiver { + @SuppressWarnings("deprecation") @Override public void onReceive(Context context, Intent intent) { Player player = PlayerNotificationManager.this.player; @@ -1382,6 +1388,8 @@ public void onReceive(Context context, Intent intent) { if (player.getPlaybackState() == Player.STATE_IDLE) { if (playbackPreparer != null) { playbackPreparer.preparePlayback(); + } else { + controlDispatcher.dispatchPrepare(player); } } else if (player.getPlaybackState() == Player.STATE_ENDED) { controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java index bb9306c7a95..3143d3d70b8 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java @@ -982,11 +982,15 @@ public void setControllerVisibilityListener( } /** - * Sets the {@link PlaybackPreparer}. - * - * @param playbackPreparer The {@link PlaybackPreparer}, or null to remove the current playback - * preparer. + * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} instead. The view calls {@link + * ControlDispatcher#dispatchPrepare(Player)} instead of {@link + * PlaybackPreparer#preparePlayback()}. The {@link DefaultControlDispatcher} that the view + * uses by default, calls {@link Player#prepare()}. If you wish to customize this behaviour, + * you can provide a custom implementation of {@link + * ControlDispatcher#dispatchPrepare(Player)}. */ + @SuppressWarnings("deprecation") + @Deprecated public void setPlaybackPreparer(@Nullable PlaybackPreparer playbackPreparer) { Assertions.checkStateNotNull(controller); controller.setPlaybackPreparer(playbackPreparer); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java index f17404b7a23..3cff0ef3cb5 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java @@ -834,11 +834,15 @@ public void setProgressUpdateListener(@Nullable ProgressUpdateListener listener) } /** - * Sets the {@link PlaybackPreparer}. - * - * @param playbackPreparer The {@link PlaybackPreparer}, or null to remove the current playback - * preparer. + * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} instead. The view calls {@link + * ControlDispatcher#dispatchPrepare(Player)} instead of {@link + * PlaybackPreparer#preparePlayback()}. The {@link DefaultControlDispatcher} that the view + * uses by default, calls {@link Player#prepare()}. If you wish to customize this behaviour, + * you can provide a custom implementation of {@link + * ControlDispatcher#dispatchPrepare(Player)}. */ + @SuppressWarnings("deprecation") + @Deprecated public void setPlaybackPreparer(@Nullable PlaybackPreparer playbackPreparer) { this.playbackPreparer = playbackPreparer; } @@ -1698,11 +1702,14 @@ private void dispatchPlayPause(Player player) { } } + @SuppressWarnings("deprecation") private void dispatchPlay(Player player) { @State int state = player.getPlaybackState(); if (state == Player.STATE_IDLE) { if (playbackPreparer != null) { playbackPreparer.preparePlayback(); + } else { + controlDispatcher.dispatchPrepare(player); } } else if (state == Player.STATE_ENDED) { seekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java index 0c018a30682..871ed8919cc 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java @@ -45,6 +45,7 @@ import androidx.core.content.ContextCompat; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ControlDispatcher; +import com.google.android.exoplayer2.DefaultControlDispatcher; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.PlaybackPreparer; import com.google.android.exoplayer2.Player; @@ -977,11 +978,15 @@ public void setControllerOnFullScreenModeChangedListener( } /** - * Sets the {@link PlaybackPreparer}. - * - * @param playbackPreparer The {@link PlaybackPreparer}, or null to remove the current playback - * preparer. + * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} instead. The view calls {@link + * ControlDispatcher#dispatchPrepare(Player)} instead of {@link + * PlaybackPreparer#preparePlayback()}. The {@link DefaultControlDispatcher} that the view + * uses by default, calls {@link Player#prepare()}. If you wish to customize this behaviour, + * you can provide a custom implementation of {@link + * ControlDispatcher#dispatchPrepare(Player)}. */ + @SuppressWarnings("deprecation") + @Deprecated public void setPlaybackPreparer(@Nullable PlaybackPreparer playbackPreparer) { Assertions.checkStateNotNull(controller); controller.setPlaybackPreparer(playbackPreparer);