Use view binding (PlayerBinding) in VideoPlayer.

This commit is contained in:
Isira Seneviratne 2020-12-23 06:25:57 +05:30 committed by Stypox
parent 92a87a5ed2
commit 0c86a4e608
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
5 changed files with 385 additions and 546 deletions

View File

@ -225,13 +225,6 @@ public abstract class BasePlayer implements
this.renderFactory = new DefaultRenderersFactory(context); this.renderFactory = new DefaultRenderersFactory(context);
} }
public void setup() {
if (simpleExoPlayer == null) {
initPlayer(true);
}
initListeners();
}
public void initPlayer(final boolean playOnReady) { public void initPlayer(final boolean playOnReady) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "initPlayer() called with: playOnReady = [" + playOnReady + "]"); Log.d(TAG, "initPlayer() called with: playOnReady = [" + playOnReady + "]");

View File

@ -26,6 +26,7 @@ import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
@ -33,8 +34,8 @@ import android.view.WindowManager;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import org.schabi.newpipe.databinding.PlayerBinding;
import org.schabi.newpipe.App; import org.schabi.newpipe.App;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
@ -102,10 +103,10 @@ public final class MainPlayer extends Service {
} }
private void createView() { private void createView() {
final View layout = View.inflate(this, R.layout.player, null); final PlayerBinding binding = PlayerBinding.inflate(LayoutInflater.from(this));
playerImpl = new VideoPlayerImpl(this); playerImpl = new VideoPlayerImpl(this);
playerImpl.setup(layout); playerImpl.setup(binding);
playerImpl.shouldUpdateOnProgress = true; playerImpl.shouldUpdateOnProgress = true;
NotificationUtil.getInstance().createNotificationAndStartForeground(playerImpl, this); NotificationUtil.getInstance().createNotificationAndStartForeground(playerImpl, this);

View File

@ -33,21 +33,18 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffColorFilter;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import androidx.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.ProgressBar;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.content.res.AppCompatResources;
import androidx.preference.PreferenceManager;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
@ -62,6 +59,7 @@ import com.google.android.exoplayer2.ui.SubtitleView;
import com.google.android.exoplayer2.video.VideoListener; import com.google.android.exoplayer2.video.VideoListener;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.PlayerBinding;
import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
@ -84,7 +82,7 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
* *
* @author mauriciocolli * @author mauriciocolli
*/ */
@SuppressWarnings({"WeakerAccess", "unused"}) @SuppressWarnings({"WeakerAccess"})
public abstract class VideoPlayer extends BasePlayer public abstract class VideoPlayer extends BasePlayer
implements VideoListener, implements VideoListener,
SeekBar.OnSeekBarChangeListener, SeekBar.OnSeekBarChangeListener,
@ -117,34 +115,11 @@ public abstract class VideoPlayer extends BasePlayer
// Views // Views
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
private View rootView; protected PlayerBinding binding;
private ExpandableSurfaceView surfaceView; protected SeekBar playbackSeekBar;
private View surfaceForeground; protected TextView qualityTextView;
protected TextView playbackSpeed;
private View loadingPanel;
private ImageView endScreen;
private ImageView controlAnimationView;
private View controlsRoot;
private TextView currentDisplaySeek;
private View playerTopShadow;
private View playerBottomShadow;
private View bottomControlsRoot;
private SeekBar playbackSeekBar;
private TextView playbackCurrentTime;
private TextView playbackEndTime;
private TextView playbackLiveSync;
private TextView playbackSpeedTextView;
private LinearLayout topControlsRoot;
private TextView qualityTextView;
private SubtitleView subtitleView;
private TextView resizeView;
private TextView captionTextView;
private ValueAnimator controlViewAnimator; private ValueAnimator controlViewAnimator;
private final Handler controlsVisibilityHandler = new Handler(); private final Handler controlsVisibilityHandler = new Handler();
@ -162,7 +137,7 @@ public abstract class VideoPlayer extends BasePlayer
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
public VideoPlayer(final String debugTag, final Context context) { protected VideoPlayer(final String debugTag, final Context context) {
super(context); super(context);
this.TAG = debugTag; this.TAG = debugTag;
this.resolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver()); this.resolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver());
@ -178,54 +153,37 @@ public abstract class VideoPlayer extends BasePlayer
return false; return false;
} }
public void setup(final View view) { public void setup(@NonNull final PlayerBinding playerBinding) {
initViews(view); initViews(playerBinding);
setup(); if (simpleExoPlayer == null) {
initPlayer(true);
}
initListeners();
} }
public void initViews(final View view) { public void initViews(@NonNull final PlayerBinding playerBinding) {
this.rootView = view; binding = playerBinding;
this.surfaceView = view.findViewById(R.id.surfaceView); playbackSeekBar = (SeekBar) binding.playbackSeekBar;
this.surfaceForeground = view.findViewById(R.id.surfaceForeground); qualityTextView = (TextView) binding.qualityTextView;
this.loadingPanel = view.findViewById(R.id.loading_panel); playbackSpeed = (TextView) binding.playbackSpeed;
this.endScreen = view.findViewById(R.id.endScreen);
this.controlAnimationView = view.findViewById(R.id.controlAnimationView);
this.controlsRoot = view.findViewById(R.id.playbackControlRoot);
this.currentDisplaySeek = view.findViewById(R.id.currentDisplaySeek);
this.playerTopShadow = view.findViewById(R.id.playerTopShadow);
this.playerBottomShadow = view.findViewById(R.id.playerBottomShadow);
this.playbackSeekBar = view.findViewById(R.id.playbackSeekBar);
this.playbackCurrentTime = view.findViewById(R.id.playbackCurrentTime);
this.playbackEndTime = view.findViewById(R.id.playbackEndTime);
this.playbackLiveSync = view.findViewById(R.id.playbackLiveSync);
this.playbackSpeedTextView = view.findViewById(R.id.playbackSpeed);
this.bottomControlsRoot = view.findViewById(R.id.bottomControls);
this.topControlsRoot = view.findViewById(R.id.topControls);
this.qualityTextView = view.findViewById(R.id.qualityTextView);
this.subtitleView = view.findViewById(R.id.subtitleView);
final float captionScale = PlayerHelper.getCaptionScale(context); final float captionScale = PlayerHelper.getCaptionScale(context);
final CaptionStyleCompat captionStyle = PlayerHelper.getCaptionStyle(context); final CaptionStyleCompat captionStyle = PlayerHelper.getCaptionStyle(context);
setupSubtitleView(subtitleView, captionScale, captionStyle); setupSubtitleView(binding.subtitleView, captionScale, captionStyle);
this.resizeView = view.findViewById(R.id.resizeTextView); ((TextView) binding.resizeTextView).setText(PlayerHelper.resizeTypeOf(context,
resizeView.setText(PlayerHelper binding.surfaceView.getResizeMode()));
.resizeTypeOf(context, getSurfaceView().getResizeMode()));
this.captionTextView = view.findViewById(R.id.captionTextView); playbackSeekBar.getThumb().setColorFilter(new PorterDuffColorFilter(Color.RED,
PorterDuff.Mode.SRC_IN));
playbackSeekBar.getProgressDrawable().setColorFilter(new PorterDuffColorFilter(Color.RED,
PorterDuff.Mode.MULTIPLY));
playbackSeekBar.getThumb() qualityPopupMenu = new PopupMenu(context, qualityTextView);
.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN)); playbackSpeedPopupMenu = new PopupMenu(context, playbackSpeed);
this.playbackSeekBar.getProgressDrawable() captionPopupMenu = new PopupMenu(context, binding.captionTextView);
.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY));
this.qualityPopupMenu = new PopupMenu(context, qualityTextView); binding.progressBarLoadingPanel.getIndeterminateDrawable()
this.playbackSpeedPopupMenu = new PopupMenu(context, playbackSpeedTextView);
this.captionPopupMenu = new PopupMenu(context, captionTextView);
((ProgressBar) this.loadingPanel.findViewById(R.id.progressBarLoadingPanel))
.getIndeterminateDrawable()
.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); .setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY));
} }
@ -235,11 +193,11 @@ public abstract class VideoPlayer extends BasePlayer
@Override @Override
public void initListeners() { public void initListeners() {
playbackSeekBar.setOnSeekBarChangeListener(this); playbackSeekBar.setOnSeekBarChangeListener(this);
playbackSpeedTextView.setOnClickListener(this); binding.playbackSpeed.setOnClickListener(this);
qualityTextView.setOnClickListener(this); binding.qualityTextView.setOnClickListener(this);
captionTextView.setOnClickListener(this); binding.captionTextView.setOnClickListener(this);
resizeView.setOnClickListener(this); binding.resizeTextView.setOnClickListener(this);
playbackLiveSync.setOnClickListener(this); binding.playbackLiveSync.setOnClickListener(this);
} }
@Override @Override
@ -247,11 +205,11 @@ public abstract class VideoPlayer extends BasePlayer
super.initPlayer(playOnReady); super.initPlayer(playOnReady);
// Setup video view // Setup video view
simpleExoPlayer.setVideoSurfaceView(surfaceView); simpleExoPlayer.setVideoSurfaceView(binding.surfaceView);
simpleExoPlayer.addVideoListener(this); simpleExoPlayer.addVideoListener(this);
// Setup subtitle view // Setup subtitle view
simpleExoPlayer.addTextOutput(cues -> subtitleView.onCues(cues)); simpleExoPlayer.addTextOutput(binding.subtitleView);
// Setup audio session with onboard equalizer // Setup audio session with onboard equalizer
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@ -305,7 +263,7 @@ public abstract class VideoPlayer extends BasePlayer
playbackSpeedPopupMenu.getMenu().add(playbackSpeedPopupMenuGroupId, i, Menu.NONE, playbackSpeedPopupMenu.getMenu().add(playbackSpeedPopupMenuGroupId, i, Menu.NONE,
formatSpeed(PLAYBACK_SPEEDS[i])); formatSpeed(PLAYBACK_SPEEDS[i]));
} }
playbackSpeedTextView.setText(formatSpeed(getPlaybackSpeed())); playbackSpeed.setText(formatSpeed(getPlaybackSpeed()));
playbackSpeedPopupMenu.setOnMenuItemClickListener(this); playbackSpeedPopupMenu.setOnMenuItemClickListener(this);
playbackSpeedPopupMenu.setOnDismissListener(this); playbackSpeedPopupMenu.setOnDismissListener(this);
} }
@ -385,29 +343,29 @@ public abstract class VideoPlayer extends BasePlayer
final MediaSourceTag tag = getCurrentMetadata(); final MediaSourceTag tag = getCurrentMetadata();
final StreamInfo metadata = tag.getMetadata(); final StreamInfo metadata = tag.getMetadata();
qualityTextView.setVisibility(View.GONE); binding.qualityTextView.setVisibility(View.GONE);
playbackSpeedTextView.setVisibility(View.GONE); binding.playbackSpeed.setVisibility(View.GONE);
playbackEndTime.setVisibility(View.GONE); binding.playbackEndTime.setVisibility(View.GONE);
playbackLiveSync.setVisibility(View.GONE); binding.playbackLiveSync.setVisibility(View.GONE);
switch (metadata.getStreamType()) { switch (metadata.getStreamType()) {
case AUDIO_STREAM: case AUDIO_STREAM:
surfaceView.setVisibility(View.GONE); binding.surfaceView.setVisibility(View.GONE);
endScreen.setVisibility(View.VISIBLE); binding.endScreen.setVisibility(View.VISIBLE);
playbackEndTime.setVisibility(View.VISIBLE); binding.playbackEndTime.setVisibility(View.VISIBLE);
break; break;
case AUDIO_LIVE_STREAM: case AUDIO_LIVE_STREAM:
surfaceView.setVisibility(View.GONE); binding.surfaceView.setVisibility(View.GONE);
endScreen.setVisibility(View.VISIBLE); binding.endScreen.setVisibility(View.VISIBLE);
playbackLiveSync.setVisibility(View.VISIBLE); binding.playbackLiveSync.setVisibility(View.VISIBLE);
break; break;
case LIVE_STREAM: case LIVE_STREAM:
surfaceView.setVisibility(View.VISIBLE); binding.surfaceView.setVisibility(View.VISIBLE);
endScreen.setVisibility(View.GONE); binding.endScreen.setVisibility(View.GONE);
playbackLiveSync.setVisibility(View.VISIBLE); binding.playbackLiveSync.setVisibility(View.VISIBLE);
break; break;
case VIDEO_STREAM: case VIDEO_STREAM:
@ -420,16 +378,16 @@ public abstract class VideoPlayer extends BasePlayer
selectedStreamIndex = tag.getSelectedVideoStreamIndex(); selectedStreamIndex = tag.getSelectedVideoStreamIndex();
buildQualityMenu(); buildQualityMenu();
qualityTextView.setVisibility(View.VISIBLE); binding.qualityTextView.setVisibility(View.VISIBLE);
surfaceView.setVisibility(View.VISIBLE); binding.surfaceView.setVisibility(View.VISIBLE);
default: default:
endScreen.setVisibility(View.GONE); binding.endScreen.setVisibility(View.GONE);
playbackEndTime.setVisibility(View.VISIBLE); binding.playbackEndTime.setVisibility(View.VISIBLE);
break; break;
} }
buildPlaybackSpeedMenu(); buildPlaybackSpeedMenu();
playbackSpeedTextView.setVisibility(View.VISIBLE); binding.playbackSpeed.setVisibility(View.VISIBLE);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -438,6 +396,7 @@ public abstract class VideoPlayer extends BasePlayer
protected abstract VideoPlaybackResolver.QualityResolver getQualityResolver(); protected abstract VideoPlaybackResolver.QualityResolver getQualityResolver();
@Override
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) { protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
super.onMetadataChanged(tag); super.onMetadataChanged(tag);
updateStreamRelatedViews(); updateStreamRelatedViews();
@ -458,15 +417,15 @@ public abstract class VideoPlayer extends BasePlayer
super.onBlocked(); super.onBlocked();
controlsVisibilityHandler.removeCallbacksAndMessages(null); controlsVisibilityHandler.removeCallbacksAndMessages(null);
animateView(controlsRoot, false, DEFAULT_CONTROLS_DURATION); animateView(binding.playbackControlRoot, false, DEFAULT_CONTROLS_DURATION);
playbackSeekBar.setEnabled(false); playbackSeekBar.setEnabled(false);
playbackSeekBar.getThumb() playbackSeekBar.getThumb().setColorFilter(new PorterDuffColorFilter(Color.RED,
.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN)); PorterDuff.Mode.SRC_IN));
loadingPanel.setBackgroundColor(Color.BLACK); binding.loadingPanel.setBackgroundColor(Color.BLACK);
animateView(loadingPanel, true, 0); animateView(binding.loadingPanel, true, 0);
animateView(surfaceForeground, true, 100); animateView(binding.surfaceForeground, true, 100);
} }
@Override @Override
@ -478,12 +437,13 @@ public abstract class VideoPlayer extends BasePlayer
showAndAnimateControl(-1, true); showAndAnimateControl(-1, true);
playbackSeekBar.setEnabled(true); playbackSeekBar.setEnabled(true);
playbackSeekBar.getThumb() playbackSeekBar.getThumb().setColorFilter(new PorterDuffColorFilter(Color.RED,
.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN)); PorterDuff.Mode.SRC_IN));
loadingPanel.setVisibility(View.GONE); binding.loadingPanel.setVisibility(View.GONE);
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200); animateView(binding.currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false,
200);
} }
@Override @Override
@ -491,7 +451,7 @@ public abstract class VideoPlayer extends BasePlayer
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onBuffering() called"); Log.d(TAG, "onBuffering() called");
} }
loadingPanel.setBackgroundColor(Color.TRANSPARENT); binding.loadingPanel.setBackgroundColor(Color.TRANSPARENT);
} }
@Override @Override
@ -500,7 +460,7 @@ public abstract class VideoPlayer extends BasePlayer
Log.d(TAG, "onPaused() called"); Log.d(TAG, "onPaused() called");
} }
showControls(400); showControls(400);
loadingPanel.setVisibility(View.GONE); binding.loadingPanel.setVisibility(View.GONE);
} }
@Override @Override
@ -516,10 +476,11 @@ public abstract class VideoPlayer extends BasePlayer
super.onCompleted(); super.onCompleted();
showControls(500); showControls(500);
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200); animateView(binding.currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false,
loadingPanel.setVisibility(View.GONE); 200);
binding.loadingPanel.setVisibility(View.GONE);
animateView(surfaceForeground, true, 100); animateView(binding.surfaceForeground, true, 100);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -527,16 +488,16 @@ public abstract class VideoPlayer extends BasePlayer
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override @Override
public void onTracksChanged(final TrackGroupArray trackGroups, public void onTracksChanged(@NonNull final TrackGroupArray trackGroups,
final TrackSelectionArray trackSelections) { @NonNull final TrackSelectionArray trackSelections) {
super.onTracksChanged(trackGroups, trackSelections); super.onTracksChanged(trackGroups, trackSelections);
onTextTrackUpdate(); onTextTrackUpdate();
} }
@Override @Override
public void onPlaybackParametersChanged(final PlaybackParameters playbackParameters) { public void onPlaybackParametersChanged(@NonNull final PlaybackParameters playbackParameters) {
super.onPlaybackParametersChanged(playbackParameters); super.onPlaybackParametersChanged(playbackParameters);
playbackSpeedTextView.setText(formatSpeed(playbackParameters.speed)); playbackSpeed.setText(formatSpeed(playbackParameters.speed));
} }
@Override @Override
@ -550,12 +511,12 @@ public abstract class VideoPlayer extends BasePlayer
+ "unappliedRotationDegrees = [" + unappliedRotationDegrees + "], " + "unappliedRotationDegrees = [" + unappliedRotationDegrees + "], "
+ "pixelWidthHeightRatio = [" + pixelWidthHeightRatio + "]"); + "pixelWidthHeightRatio = [" + pixelWidthHeightRatio + "]");
} }
getSurfaceView().setAspectRatio(((float) width) / height); binding.surfaceView.setAspectRatio(((float) width) / height);
} }
@Override @Override
public void onRenderedFirstFrame() { public void onRenderedFirstFrame() {
animateView(surfaceForeground, false, 100); animateView(binding.surfaceForeground, false, 100);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -565,12 +526,12 @@ public abstract class VideoPlayer extends BasePlayer
private void onTextTrackUpdate() { private void onTextTrackUpdate() {
final int textRenderer = getRendererIndex(C.TRACK_TYPE_TEXT); final int textRenderer = getRendererIndex(C.TRACK_TYPE_TEXT);
if (captionTextView == null) { if (binding == null) {
return; return;
} }
if (trackSelector.getCurrentMappedTrackInfo() == null if (trackSelector.getCurrentMappedTrackInfo() == null
|| textRenderer == RENDERER_UNAVAILABLE) { || textRenderer == RENDERER_UNAVAILABLE) {
captionTextView.setVisibility(View.GONE); binding.captionTextView.setVisibility(View.GONE);
return; return;
} }
@ -593,11 +554,12 @@ public abstract class VideoPlayer extends BasePlayer
if (trackSelector.getParameters().getRendererDisabled(textRenderer) if (trackSelector.getParameters().getRendererDisabled(textRenderer)
|| preferredLanguage == null || (!availableLanguages.contains(preferredLanguage) || preferredLanguage == null || (!availableLanguages.contains(preferredLanguage)
&& !containsCaseInsensitive(availableLanguages, preferredLanguage))) { && !containsCaseInsensitive(availableLanguages, preferredLanguage))) {
captionTextView.setText(R.string.caption_none); binding.captionTextView.setText(R.string.caption_none);
} else { } else {
captionTextView.setText(preferredLanguage); binding.captionTextView.setText(preferredLanguage);
} }
captionTextView.setVisibility(availableLanguages.isEmpty() ? View.GONE : View.VISIBLE); binding.captionTextView.setVisibility(availableLanguages.isEmpty() ? View.GONE
: View.VISIBLE);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -611,8 +573,8 @@ public abstract class VideoPlayer extends BasePlayer
} }
playbackSeekBar.setMax((int) simpleExoPlayer.getDuration()); playbackSeekBar.setMax((int) simpleExoPlayer.getDuration());
playbackEndTime.setText(getTimeString((int) simpleExoPlayer.getDuration())); binding.playbackEndTime.setText(getTimeString((int) simpleExoPlayer.getDuration()));
playbackSpeedTextView.setText(formatSpeed(getPlaybackSpeed())); playbackSpeed.setText(formatSpeed(getPlaybackSpeed()));
super.onPrepared(playWhenReady); super.onPrepared(playWhenReady);
} }
@ -620,8 +582,8 @@ public abstract class VideoPlayer extends BasePlayer
@Override @Override
public void destroy() { public void destroy() {
super.destroy(); super.destroy();
if (endScreen != null) { if (binding != null) {
endScreen.setImageBitmap(null); binding.endScreen.setImageBitmap(null);
} }
} }
@ -633,14 +595,14 @@ public abstract class VideoPlayer extends BasePlayer
} }
if (duration != playbackSeekBar.getMax()) { if (duration != playbackSeekBar.getMax()) {
playbackEndTime.setText(getTimeString(duration)); binding.playbackEndTime.setText(getTimeString(duration));
playbackSeekBar.setMax(duration); playbackSeekBar.setMax(duration);
} }
if (currentState != STATE_PAUSED) { if (currentState != STATE_PAUSED) {
if (currentState != STATE_PAUSED_SEEK) { if (currentState != STATE_PAUSED_SEEK) {
playbackSeekBar.setProgress(currentProgress); playbackSeekBar.setProgress(currentProgress);
} }
playbackCurrentTime.setText(getTimeString(currentProgress)); binding.playbackCurrentTime.setText(getTimeString(currentProgress));
} }
if (simpleExoPlayer.isLoading() || bufferPercent > 90) { if (simpleExoPlayer.isLoading() || bufferPercent > 90) {
playbackSeekBar.setSecondaryProgress( playbackSeekBar.setSecondaryProgress(
@ -652,7 +614,7 @@ public abstract class VideoPlayer extends BasePlayer
+ "currentProgress = [" + currentProgress + "], " + "currentProgress = [" + currentProgress + "], "
+ "duration = [" + duration + "], bufferPercent = [" + bufferPercent + "]"); + "duration = [" + duration + "], bufferPercent = [" + bufferPercent + "]");
} }
playbackLiveSync.setClickable(!isLiveEdge()); binding.playbackLiveSync.setClickable(!isLiveEdge());
} }
@Override @Override
@ -660,7 +622,7 @@ public abstract class VideoPlayer extends BasePlayer
final Bitmap loadedImage) { final Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage); super.onLoadingComplete(imageUri, view, loadedImage);
if (loadedImage != null) { if (loadedImage != null) {
endScreen.setImageBitmap(loadedImage); binding.endScreen.setImageBitmap(loadedImage);
} }
} }
@ -689,15 +651,15 @@ public abstract class VideoPlayer extends BasePlayer
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onClick() called with: v = [" + v + "]"); Log.d(TAG, "onClick() called with: v = [" + v + "]");
} }
if (v.getId() == qualityTextView.getId()) { if (v.getId() == binding.qualityTextView.getId()) {
onQualitySelectorClicked(); onQualitySelectorClicked();
} else if (v.getId() == playbackSpeedTextView.getId()) { } else if (v.getId() == binding.playbackSpeed.getId()) {
onPlaybackSpeedClicked(); onPlaybackSpeedClicked();
} else if (v.getId() == resizeView.getId()) { } else if (v.getId() == binding.resizeTextView.getId()) {
onResizeClicked(); onResizeClicked();
} else if (v.getId() == captionTextView.getId()) { } else if (v.getId() == binding.captionTextView.getId()) {
onCaptionClicked(); onCaptionClicked();
} else if (v.getId() == playbackLiveSync.getId()) { } else if (v.getId() == binding.playbackLiveSync.getId()) {
seekToDefault(); seekToDefault();
} }
} }
@ -732,7 +694,7 @@ public abstract class VideoPlayer extends BasePlayer
final float speed = PLAYBACK_SPEEDS[speedIndex]; final float speed = PLAYBACK_SPEEDS[speedIndex];
setPlaybackSpeed(speed); setPlaybackSpeed(speed);
playbackSpeedTextView.setText(formatSpeed(speed)); playbackSpeed.setText(formatSpeed(speed));
} }
return false; return false;
@ -786,16 +748,17 @@ public abstract class VideoPlayer extends BasePlayer
} }
void onResizeClicked() { void onResizeClicked() {
if (getSurfaceView() != null) { if (binding != null) {
final int currentResizeMode = getSurfaceView().getResizeMode(); final int currentResizeMode = binding.surfaceView.getResizeMode();
final int newResizeMode = nextResizeMode(currentResizeMode); final int newResizeMode = nextResizeMode(currentResizeMode);
setResizeMode(newResizeMode); setResizeMode(newResizeMode);
} }
} }
protected void setResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode) { protected void setResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode) {
getSurfaceView().setResizeMode(resizeMode); binding.surfaceView.setResizeMode(resizeMode);
getResizeView().setText(PlayerHelper.resizeTypeOf(context, resizeMode)); ((TextView) binding.resizeTextView).setText(PlayerHelper.resizeTypeOf(context,
resizeMode));
} }
protected abstract int nextResizeMode(@AspectRatioFrameLayout.ResizeMode int resizeMode); protected abstract int nextResizeMode(@AspectRatioFrameLayout.ResizeMode int resizeMode);
@ -811,9 +774,8 @@ public abstract class VideoPlayer extends BasePlayer
Log.d(TAG, "onProgressChanged() called with: " Log.d(TAG, "onProgressChanged() called with: "
+ "seekBar = [" + seekBar + "], progress = [" + progress + "]"); + "seekBar = [" + seekBar + "], progress = [" + progress + "]");
} }
//if (fromUser) playbackCurrentTime.setText(getTimeString(progress));
if (fromUser) { if (fromUser) {
currentDisplaySeek.setText(getTimeString(progress)); binding.currentDisplaySeek.setText(getTimeString(progress));
} }
} }
@ -832,7 +794,7 @@ public abstract class VideoPlayer extends BasePlayer
} }
showControls(0); showControls(0);
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, true, animateView(binding.currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, true,
DEFAULT_CONTROLS_DURATION); DEFAULT_CONTROLS_DURATION);
} }
@ -847,8 +809,9 @@ public abstract class VideoPlayer extends BasePlayer
simpleExoPlayer.setPlayWhenReady(true); simpleExoPlayer.setPlayWhenReady(true);
} }
playbackCurrentTime.setText(getTimeString(seekBar.getProgress())); binding.playbackCurrentTime.setText(getTimeString(seekBar.getProgress()));
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200); animateView(binding.currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false,
200);
if (getCurrentState() == STATE_PAUSED_SEEK) { if (getCurrentState() == STATE_PAUSED_SEEK) {
changeState(STATE_BUFFERING); changeState(STATE_BUFFERING);
@ -877,7 +840,8 @@ public abstract class VideoPlayer extends BasePlayer
} }
public boolean isControlsVisible() { public boolean isControlsVisible() {
return controlsRoot != null && controlsRoot.getVisibility() == View.VISIBLE; return binding != null
&& binding.playbackControlRoot.getVisibility() == View.VISIBLE;
} }
/** /**
@ -900,8 +864,9 @@ public abstract class VideoPlayer extends BasePlayer
} }
if (drawableId == -1) { if (drawableId == -1) {
if (controlAnimationView.getVisibility() == View.VISIBLE) { if (binding.controlAnimationView.getVisibility() == View.VISIBLE) {
controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(controlAnimationView, controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(
binding.controlAnimationView,
PropertyValuesHolder.ofFloat(View.ALPHA, 1.0f, 0.0f), PropertyValuesHolder.ofFloat(View.ALPHA, 1.0f, 0.0f),
PropertyValuesHolder.ofFloat(View.SCALE_X, 1.4f, 1.0f), PropertyValuesHolder.ofFloat(View.SCALE_X, 1.4f, 1.0f),
PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.4f, 1.0f) PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.4f, 1.0f)
@ -909,7 +874,7 @@ public abstract class VideoPlayer extends BasePlayer
controlViewAnimator.addListener(new AnimatorListenerAdapter() { controlViewAnimator.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(final Animator animation) { public void onAnimationEnd(final Animator animation) {
controlAnimationView.setVisibility(View.GONE); binding.controlAnimationView.setVisibility(View.GONE);
} }
}); });
controlViewAnimator.start(); controlViewAnimator.start();
@ -923,7 +888,8 @@ public abstract class VideoPlayer extends BasePlayer
final float alphaTo = goneOnEnd ? 0f : 1f; final float alphaTo = goneOnEnd ? 0f : 1f;
controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(controlAnimationView, controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(
binding.controlAnimationView,
PropertyValuesHolder.ofFloat(View.ALPHA, alphaFrom, alphaTo), PropertyValuesHolder.ofFloat(View.ALPHA, alphaFrom, alphaTo),
PropertyValuesHolder.ofFloat(View.SCALE_X, scaleFrom, scaleTo), PropertyValuesHolder.ofFloat(View.SCALE_X, scaleFrom, scaleTo),
PropertyValuesHolder.ofFloat(View.SCALE_Y, scaleFrom, scaleTo) PropertyValuesHolder.ofFloat(View.SCALE_Y, scaleFrom, scaleTo)
@ -932,17 +898,14 @@ public abstract class VideoPlayer extends BasePlayer
controlViewAnimator.addListener(new AnimatorListenerAdapter() { controlViewAnimator.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(final Animator animation) { public void onAnimationEnd(final Animator animation) {
if (goneOnEnd) { binding.controlAnimationView.setVisibility(goneOnEnd ? View.GONE
controlAnimationView.setVisibility(View.GONE); : View.VISIBLE);
} else {
controlAnimationView.setVisibility(View.VISIBLE);
}
} }
}); });
binding.controlAnimationView.setVisibility(View.VISIBLE);
controlAnimationView.setVisibility(View.VISIBLE); binding.controlAnimationView.setImageDrawable(AppCompatResources.getDrawable(context,
controlAnimationView.setImageDrawable(AppCompatResources.getDrawable(context, drawableId)); drawableId));
controlViewAnimator.start(); controlViewAnimator.start();
} }
@ -955,12 +918,12 @@ public abstract class VideoPlayer extends BasePlayer
Log.d(TAG, "showControlsThenHide() called"); Log.d(TAG, "showControlsThenHide() called");
} }
final int hideTime = controlsRoot.isInTouchMode() final int hideTime = binding.playbackControlRoot.isInTouchMode()
? DEFAULT_CONTROLS_HIDE_TIME ? DEFAULT_CONTROLS_HIDE_TIME
: DPAD_CONTROLS_HIDE_TIME; : DPAD_CONTROLS_HIDE_TIME;
showHideShadow(true, DEFAULT_CONTROLS_DURATION, 0); showHideShadow(true, DEFAULT_CONTROLS_DURATION, 0);
animateView(controlsRoot, true, DEFAULT_CONTROLS_DURATION, 0, animateView(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, 0,
() -> hideControls(DEFAULT_CONTROLS_DURATION, hideTime)); () -> hideControls(DEFAULT_CONTROLS_DURATION, hideTime));
} }
@ -970,17 +933,18 @@ public abstract class VideoPlayer extends BasePlayer
} }
controlsVisibilityHandler.removeCallbacksAndMessages(null); controlsVisibilityHandler.removeCallbacksAndMessages(null);
showHideShadow(true, duration, 0); showHideShadow(true, duration, 0);
animateView(controlsRoot, true, duration); animateView(binding.playbackControlRoot, true, duration);
} }
public void safeHideControls(final long duration, final long delay) { public void safeHideControls(final long duration, final long delay) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "safeHideControls() called with: delay = [" + delay + "]"); Log.d(TAG, "safeHideControls() called with: delay = [" + delay + "]");
} }
if (rootView.isInTouchMode()) { if (binding.getRoot().isInTouchMode()) {
controlsVisibilityHandler.removeCallbacksAndMessages(null); controlsVisibilityHandler.removeCallbacksAndMessages(null);
controlsVisibilityHandler.postDelayed( controlsVisibilityHandler.postDelayed(
() -> animateView(controlsRoot, false, duration), delay); () -> animateView(binding.playbackControlRoot, false, duration),
delay);
} }
} }
@ -991,7 +955,7 @@ public abstract class VideoPlayer extends BasePlayer
controlsVisibilityHandler.removeCallbacksAndMessages(null); controlsVisibilityHandler.removeCallbacksAndMessages(null);
controlsVisibilityHandler.postDelayed(() -> { controlsVisibilityHandler.postDelayed(() -> {
showHideShadow(false, duration, 0); showHideShadow(false, duration, 0);
animateView(controlsRoot, false, duration); animateView(binding.playbackControlRoot, false, duration);
}, delay); }, delay);
} }
@ -1007,13 +971,13 @@ public abstract class VideoPlayer extends BasePlayer
private Runnable hideControlsAndButtonHandler(final long duration, final View videoPlayPause) { private Runnable hideControlsAndButtonHandler(final long duration, final View videoPlayPause) {
return () -> { return () -> {
videoPlayPause.setVisibility(View.INVISIBLE); videoPlayPause.setVisibility(View.INVISIBLE);
animateView(controlsRoot, false, duration); animateView(binding.playbackControlRoot, false, duration);
}; };
} }
void showHideShadow(final boolean show, final long duration, final long delay) { void showHideShadow(final boolean show, final long duration, final long delay) {
animateView(playerTopShadow, show, duration, delay, null); animateView(binding.playerTopShadow, show, duration, delay, null);
animateView(playerBottomShadow, show, duration, delay, null); animateView(binding.playerBottomShadow, show, duration, delay, null);
} }
public abstract void hideSystemUIIfNeeded(); public abstract void hideSystemUIIfNeeded();
@ -1032,7 +996,7 @@ public abstract class VideoPlayer extends BasePlayer
} }
public ExpandableSurfaceView getSurfaceView() { public ExpandableSurfaceView getSurfaceView() {
return surfaceView; return binding.surfaceView;
} }
public boolean wasPlaying() { public boolean wasPlaying() {
@ -1050,83 +1014,23 @@ public abstract class VideoPlayer extends BasePlayer
return controlsVisibilityHandler; return controlsVisibilityHandler;
} }
@NonNull
public View getRootView() { public View getRootView() {
return rootView; return binding.getRoot();
}
public void setRootView(final View rootView) {
this.rootView = rootView;
} }
@NonNull
public View getLoadingPanel() { public View getLoadingPanel() {
return loadingPanel; return binding.loadingPanel;
} }
public ImageView getEndScreen() { @NonNull
return endScreen; public View getPlaybackControlRoot() {
} return binding.playbackControlRoot;
public ImageView getControlAnimationView() {
return controlAnimationView;
}
public View getControlsRoot() {
return controlsRoot;
}
public View getBottomControlsRoot() {
return bottomControlsRoot;
}
public SeekBar getPlaybackSeekBar() {
return playbackSeekBar;
}
public TextView getPlaybackCurrentTime() {
return playbackCurrentTime;
}
public TextView getPlaybackEndTime() {
return playbackEndTime;
}
public LinearLayout getTopControlsRoot() {
return topControlsRoot;
}
public TextView getQualityTextView() {
return qualityTextView;
}
public PopupMenu getQualityPopupMenu() {
return qualityPopupMenu;
}
public TextView getPlaybackSpeedTextView() {
return playbackSpeedTextView;
}
public PopupMenu getPlaybackSpeedPopupMenu() {
return playbackSpeedPopupMenu;
}
public View getSurfaceForeground() {
return surfaceForeground;
} }
@NonNull
public TextView getCurrentDisplaySeek() { public TextView getCurrentDisplaySeek() {
return currentDisplaySeek; return binding.currentDisplaySeek;
}
public SubtitleView getSubtitleView() {
return subtitleView;
}
public TextView getResizeView() {
return resizeView;
}
public TextView getCaptionTextView() {
return captionTextView;
} }
} }

View File

@ -77,6 +77,7 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.assist.FailReason;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.PlayerBinding;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
@ -145,45 +146,11 @@ public class VideoPlayerImpl extends VideoPlayer
private static final float MAX_GESTURE_LENGTH = 0.75f; private static final float MAX_GESTURE_LENGTH = 0.75f;
private TextView titleTextView;
private TextView channelTextView;
private RelativeLayout volumeRelativeLayout;
private ProgressBar volumeProgressBar;
private ImageView volumeImageView;
private RelativeLayout brightnessRelativeLayout;
private ProgressBar brightnessProgressBar;
private ImageView brightnessImageView;
private TextView resizingIndicator;
private ImageButton queueButton;
private ImageButton repeatButton;
private ImageButton shuffleButton;
private ImageButton playWithKodi;
private ImageButton openInBrowser;
private ImageButton fullscreenButton;
private ImageButton playerCloseButton;
private ImageButton screenRotationButton;
private ImageButton muteButton;
private ImageButton playPauseButton;
private ImageButton playPreviousButton;
private ImageButton playNextButton;
private RelativeLayout queueLayout;
private ImageButton itemsListCloseButton;
private RecyclerView itemsList;
private ItemTouchHelper itemTouchHelper; private ItemTouchHelper itemTouchHelper;
private RelativeLayout playerOverlays;
private boolean queueVisible; private boolean queueVisible;
private MainPlayer.PlayerType playerType = MainPlayer.PlayerType.VIDEO; private MainPlayer.PlayerType playerType = MainPlayer.PlayerType.VIDEO;
private ImageButton moreOptionsButton;
private ImageButton shareButton;
private View primaryControls;
private View secondaryControls;
private int maxGestureLength; private int maxGestureLength;
private boolean audioOnly = false; private boolean audioOnly = false;
@ -205,7 +172,6 @@ public class VideoPlayerImpl extends VideoPlayer
private WindowManager.LayoutParams popupLayoutParams; private WindowManager.LayoutParams popupLayoutParams;
public WindowManager windowManager; public WindowManager windowManager;
private View closingOverlayView;
private View closeOverlayView; private View closeOverlayView;
private FloatingActionButton closeOverlayButton; private FloatingActionButton closeOverlayButton;
@ -251,13 +217,13 @@ public class VideoPlayerImpl extends VideoPlayer
getRootView().setVisibility(View.VISIBLE); getRootView().setVisibility(View.VISIBLE);
initPopup(); initPopup();
initPopupCloseOverlay(); initPopupCloseOverlay();
playPauseButton.requestFocus(); binding.playPauseButton.requestFocus();
} else { } else {
getRootView().setVisibility(View.VISIBLE); getRootView().setVisibility(View.VISIBLE);
initVideoPlayer(); initVideoPlayer();
onQueueClosed(); onQueueClosed();
// Android TV: without it focus will frame the whole player // Android TV: without it focus will frame the whole player
playPauseButton.requestFocus(); binding.playPauseButton.requestFocus();
if (simpleExoPlayer.getPlayWhenReady()) { if (simpleExoPlayer.getPlayWhenReady()) {
onPlay(); onPlay();
@ -279,49 +245,14 @@ public class VideoPlayerImpl extends VideoPlayer
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@Override @Override
public void initViews(final View view) { public void initViews(@NonNull final PlayerBinding binding) {
super.initViews(view); super.initViews(binding);
this.titleTextView = view.findViewById(R.id.titleTextView);
this.channelTextView = view.findViewById(R.id.channelTextView);
this.volumeRelativeLayout = view.findViewById(R.id.volumeRelativeLayout);
this.volumeProgressBar = view.findViewById(R.id.volumeProgressBar);
this.volumeImageView = view.findViewById(R.id.volumeImageView);
this.brightnessRelativeLayout = view.findViewById(R.id.brightnessRelativeLayout);
this.brightnessProgressBar = view.findViewById(R.id.brightnessProgressBar);
this.brightnessImageView = view.findViewById(R.id.brightnessImageView);
this.resizingIndicator = view.findViewById(R.id.resizing_indicator);
this.queueButton = view.findViewById(R.id.queueButton);
this.repeatButton = view.findViewById(R.id.repeatButton);
this.shuffleButton = view.findViewById(R.id.shuffleButton);
this.playWithKodi = view.findViewById(R.id.playWithKodi);
this.openInBrowser = view.findViewById(R.id.openInBrowser);
this.fullscreenButton = view.findViewById(R.id.fullScreenButton);
this.screenRotationButton = view.findViewById(R.id.screenRotationButton);
this.playerCloseButton = view.findViewById(R.id.playerCloseButton);
this.muteButton = view.findViewById(R.id.switchMute);
this.playPauseButton = view.findViewById(R.id.playPauseButton); binding.titleTextView.setSelected(true);
this.playPreviousButton = view.findViewById(R.id.playPreviousButton); binding.channelTextView.setSelected(true);
this.playNextButton = view.findViewById(R.id.playNextButton);
this.moreOptionsButton = view.findViewById(R.id.moreOptionsButton);
this.primaryControls = view.findViewById(R.id.primaryControls);
this.secondaryControls = view.findViewById(R.id.secondaryControls);
this.shareButton = view.findViewById(R.id.share);
this.queueLayout = view.findViewById(R.id.playQueuePanel);
this.itemsListCloseButton = view.findViewById(R.id.playQueueClose);
this.itemsList = view.findViewById(R.id.playQueue);
this.playerOverlays = view.findViewById(R.id.player_overlays);
closingOverlayView = view.findViewById(R.id.closingOverlay);
titleTextView.setSelected(true);
channelTextView.setSelected(true);
// Prevent hiding of bottom sheet via swipe inside queue // Prevent hiding of bottom sheet via swipe inside queue
this.itemsList.setNestedScrollingEnabled(false); binding.playQueue.setNestedScrollingEnabled(false);
} }
@Override @Override
@ -349,58 +280,60 @@ public class VideoPlayerImpl extends VideoPlayer
*/ */
private void setupElementsVisibility() { private void setupElementsVisibility() {
if (popupPlayerSelected()) { if (popupPlayerSelected()) {
fullscreenButton.setVisibility(View.VISIBLE); binding.fullScreenButton.setVisibility(View.VISIBLE);
screenRotationButton.setVisibility(View.GONE); binding.screenRotationButton.setVisibility(View.GONE);
getResizeView().setVisibility(View.GONE); binding.resizeTextView.setVisibility(View.GONE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.GONE); binding.metadataView.setVisibility(View.GONE);
queueButton.setVisibility(View.GONE); binding.queueButton.setVisibility(View.GONE);
moreOptionsButton.setVisibility(View.GONE); binding.moreOptionsButton.setVisibility(View.GONE);
getTopControlsRoot().setOrientation(LinearLayout.HORIZONTAL); binding.topControls.setOrientation(LinearLayout.HORIZONTAL);
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT; binding.primaryControls.getLayoutParams().width =
secondaryControls.setAlpha(1.0f); LinearLayout.LayoutParams.WRAP_CONTENT;
secondaryControls.setVisibility(View.VISIBLE); binding.secondaryControls.setAlpha(1.0f);
secondaryControls.setTranslationY(0); binding.secondaryControls.setVisibility(View.VISIBLE);
shareButton.setVisibility(View.GONE); binding.secondaryControls.setTranslationY(0);
playWithKodi.setVisibility(View.GONE); binding.share.setVisibility(View.GONE);
openInBrowser.setVisibility(View.GONE); binding.playWithKodi.setVisibility(View.GONE);
muteButton.setVisibility(View.GONE); binding.openInBrowser.setVisibility(View.GONE);
playerCloseButton.setVisibility(View.GONE); binding.switchMute.setVisibility(View.GONE);
getTopControlsRoot().bringToFront(); binding.playerCloseButton.setVisibility(View.GONE);
getTopControlsRoot().setClickable(false); binding.topControls.bringToFront();
getTopControlsRoot().setFocusable(false); binding.topControls.setClickable(false);
getBottomControlsRoot().bringToFront(); binding.topControls.setFocusable(false);
binding.bottomControls.bringToFront();
onQueueClosed(); onQueueClosed();
} else { } else {
fullscreenButton.setVisibility(View.GONE); binding.fullScreenButton.setVisibility(View.GONE);
setupScreenRotationButton(); setupScreenRotationButton();
getResizeView().setVisibility(View.VISIBLE); binding.resizeTextView.setVisibility(View.VISIBLE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE); binding.metadataView.setVisibility(View.VISIBLE);
moreOptionsButton.setVisibility(View.VISIBLE); binding.moreOptionsButton.setVisibility(View.VISIBLE);
getTopControlsRoot().setOrientation(LinearLayout.VERTICAL); binding.topControls.setOrientation(LinearLayout.VERTICAL);
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.MATCH_PARENT; binding.primaryControls.getLayoutParams().width =
secondaryControls.setVisibility(View.INVISIBLE); LinearLayout.LayoutParams.MATCH_PARENT;
moreOptionsButton.setImageDrawable(AppCompatResources.getDrawable(service, binding.secondaryControls.setVisibility(View.INVISIBLE);
binding.moreOptionsButton.setImageDrawable(AppCompatResources.getDrawable(service,
R.drawable.ic_expand_more_white_24dp)); R.drawable.ic_expand_more_white_24dp));
shareButton.setVisibility(View.VISIBLE); binding.share.setVisibility(View.VISIBLE);
showHideKodiButton(); showHideKodiButton();
openInBrowser.setVisibility(View.VISIBLE); binding.openInBrowser.setVisibility(View.VISIBLE);
muteButton.setVisibility(View.VISIBLE); binding.switchMute.setVisibility(View.VISIBLE);
playerCloseButton.setVisibility(isFullscreen ? View.GONE : View.VISIBLE); binding.playerCloseButton.setVisibility(isFullscreen ? View.GONE : View.VISIBLE);
// Top controls have a large minHeight which is allows to drag the player // Top controls have a large minHeight which is allows to drag the player
// down in fullscreen mode (just larger area to make easy to locate by finger) // down in fullscreen mode (just larger area to make easy to locate by finger)
getTopControlsRoot().setClickable(true); binding.topControls.setClickable(true);
getTopControlsRoot().setFocusable(true); binding.topControls.setFocusable(true);
} }
if (!isFullscreen()) { if (!isFullscreen()) {
titleTextView.setVisibility(View.GONE); binding.titleTextView.setVisibility(View.GONE);
channelTextView.setVisibility(View.GONE); binding.channelTextView.setVisibility(View.GONE);
} else { } else {
titleTextView.setVisibility(View.VISIBLE); binding.titleTextView.setVisibility(View.VISIBLE);
channelTextView.setVisibility(View.VISIBLE); binding.channelTextView.setVisibility(View.VISIBLE);
} }
setMuteButton(muteButton, isMuted()); setMuteButton(binding.switchMute, isMuted());
animateRotation(moreOptionsButton, DEFAULT_CONTROLS_DURATION, 0); animateRotation(binding.moreOptionsButton, DEFAULT_CONTROLS_DURATION, 0);
} }
/** /**
@ -413,15 +346,15 @@ public class VideoPlayerImpl extends VideoPlayer
.getDimensionPixelSize(R.dimen.player_popup_controls_padding); .getDimensionPixelSize(R.dimen.player_popup_controls_padding);
final int buttonsPadding = service.getResources() final int buttonsPadding = service.getResources()
.getDimensionPixelSize(R.dimen.player_popup_buttons_padding); .getDimensionPixelSize(R.dimen.player_popup_buttons_padding);
getTopControlsRoot().setPaddingRelative(controlsPadding, 0, controlsPadding, 0); binding.topControls.setPaddingRelative(controlsPadding, 0, controlsPadding, 0);
getBottomControlsRoot().setPaddingRelative(controlsPadding, 0, controlsPadding, 0); binding.bottomControls.setPaddingRelative(controlsPadding, 0, controlsPadding, 0);
getQualityTextView().setPadding( binding.qualityTextView.setPadding(buttonsPadding, buttonsPadding, buttonsPadding,
buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding); buttonsPadding);
getPlaybackSpeedTextView().setPadding( binding.playbackSpeed.setPadding(buttonsPadding, buttonsPadding, buttonsPadding,
buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding); buttonsPadding);
getCaptionTextView().setPadding( binding.captionTextView.setPadding(buttonsPadding, buttonsPadding, buttonsPadding,
buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding); buttonsPadding);
getPlaybackSpeedTextView().setMinimumWidth(0); binding.playbackSpeed.setMinimumWidth(0);
} else if (videoPlayerSelected()) { } else if (videoPlayerSelected()) {
final int buttonsMinWidth = service.getResources() final int buttonsMinWidth = service.getResources()
.getDimensionPixelSize(R.dimen.player_main_buttons_min_width); .getDimensionPixelSize(R.dimen.player_main_buttons_min_width);
@ -431,16 +364,16 @@ public class VideoPlayerImpl extends VideoPlayer
.getDimensionPixelSize(R.dimen.player_main_controls_padding); .getDimensionPixelSize(R.dimen.player_main_controls_padding);
final int buttonsPadding = service.getResources() final int buttonsPadding = service.getResources()
.getDimensionPixelSize(R.dimen.player_main_buttons_padding); .getDimensionPixelSize(R.dimen.player_main_buttons_padding);
getTopControlsRoot().setPaddingRelative( binding.topControls.setPaddingRelative(controlsPadding, playerTopPadding,
controlsPadding, playerTopPadding, controlsPadding, 0); controlsPadding, 0);
getBottomControlsRoot().setPaddingRelative(controlsPadding, 0, controlsPadding, 0); binding.bottomControls.setPaddingRelative(controlsPadding, 0, controlsPadding, 0);
getQualityTextView().setPadding( binding.qualityTextView.setPadding(buttonsPadding, buttonsPadding, buttonsPadding,
buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding); buttonsPadding);
getPlaybackSpeedTextView().setPadding( binding.playbackSpeed.setPadding(buttonsPadding, buttonsPadding, buttonsPadding,
buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding); buttonsPadding);
getPlaybackSpeedTextView().setMinimumWidth(buttonsMinWidth); binding.playbackSpeed.setMinimumWidth(buttonsMinWidth);
getCaptionTextView().setPadding( binding.captionTextView.setPadding(buttonsPadding, buttonsPadding, buttonsPadding,
buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding); buttonsPadding);
} }
} }
@ -452,23 +385,23 @@ public class VideoPlayerImpl extends VideoPlayer
gestureDetector = new GestureDetector(context, listener); gestureDetector = new GestureDetector(context, listener);
getRootView().setOnTouchListener(listener); getRootView().setOnTouchListener(listener);
queueButton.setOnClickListener(this); binding.queueButton.setOnClickListener(this);
repeatButton.setOnClickListener(this); binding.repeatButton.setOnClickListener(this);
shuffleButton.setOnClickListener(this); binding.shuffleButton.setOnClickListener(this);
playPauseButton.setOnClickListener(this); binding.playPauseButton.setOnClickListener(this);
playPreviousButton.setOnClickListener(this); binding.playPreviousButton.setOnClickListener(this);
playNextButton.setOnClickListener(this); binding.playNextButton.setOnClickListener(this);
moreOptionsButton.setOnClickListener(this); binding.moreOptionsButton.setOnClickListener(this);
moreOptionsButton.setOnLongClickListener(this); binding.moreOptionsButton.setOnLongClickListener(this);
shareButton.setOnClickListener(this); binding.share.setOnClickListener(this);
fullscreenButton.setOnClickListener(this); binding.fullScreenButton.setOnClickListener(this);
screenRotationButton.setOnClickListener(this); binding.screenRotationButton.setOnClickListener(this);
playWithKodi.setOnClickListener(this); binding.playWithKodi.setOnClickListener(this);
openInBrowser.setOnClickListener(this); binding.openInBrowser.setOnClickListener(this);
playerCloseButton.setOnClickListener(this); binding.playerCloseButton.setOnClickListener(this);
muteButton.setOnClickListener(this); binding.switchMute.setOnClickListener(this);
settingsContentObserver = new ContentObserver(new Handler()) { settingsContentObserver = new ContentObserver(new Handler()) {
@Override @Override
@ -481,7 +414,8 @@ public class VideoPlayerImpl extends VideoPlayer
settingsContentObserver); settingsContentObserver);
getRootView().addOnLayoutChangeListener(this); getRootView().addOnLayoutChangeListener(this);
ViewCompat.setOnApplyWindowInsetsListener(queueLayout, (view, windowInsets) -> { ViewCompat.setOnApplyWindowInsetsListener(binding.playQueuePanel,
(view, windowInsets) -> {
final DisplayCutoutCompat cutout = windowInsets.getDisplayCutout(); final DisplayCutoutCompat cutout = windowInsets.getDisplayCutout();
if (cutout != null) { if (cutout != null) {
view.setPadding(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(), view.setPadding(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
@ -492,9 +426,9 @@ public class VideoPlayerImpl extends VideoPlayer
// PlaybackControlRoot already consumed window insets but we should pass them to // PlaybackControlRoot already consumed window insets but we should pass them to
// player_overlays too. Without it they will be off-centered // player_overlays too. Without it they will be off-centered
getControlsRoot().addOnLayoutChangeListener((v, left, top, right, bottom, binding.playbackControlRoot.addOnLayoutChangeListener(
oldLeft, oldTop, oldRight, oldBottom) -> (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
playerOverlays.setPadding( binding.playerOverlays.setPadding(
v.getPaddingLeft(), v.getPaddingLeft(),
v.getPaddingTop(), v.getPaddingTop(),
v.getPaddingRight(), v.getPaddingRight(),
@ -521,7 +455,7 @@ public class VideoPlayerImpl extends VideoPlayer
case KeyEvent.KEYCODE_DPAD_DOWN: case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_DPAD_CENTER:
if (getRootView().hasFocus() && !getControlsRoot().hasFocus()) { if (getRootView().hasFocus() && !binding.playbackControlRoot.hasFocus()) {
// do not interfere with focus in playlist etc. // do not interfere with focus in playlist etc.
return false; return false;
} }
@ -532,7 +466,7 @@ public class VideoPlayerImpl extends VideoPlayer
if (!isControlsVisible()) { if (!isControlsVisible()) {
if (!queueVisible) { if (!queueVisible) {
playPauseButton.requestFocus(); binding.playPauseButton.requestFocus();
} }
showControlsThenHide(); showControlsThenHide();
showSystemUIPartially(); showSystemUIPartially();
@ -548,13 +482,12 @@ public class VideoPlayerImpl extends VideoPlayer
public AppCompatActivity getParentActivity() { public AppCompatActivity getParentActivity() {
// ! instanceof ViewGroup means that view was added via windowManager for Popup // ! instanceof ViewGroup means that view was added via windowManager for Popup
if (getRootView() == null if (binding == null || binding.getRoot().getParent() == null
|| getRootView().getParent() == null || !(binding.getRoot().getParent() instanceof ViewGroup)) {
|| !(getRootView().getParent() instanceof ViewGroup)) {
return null; return null;
} }
final ViewGroup parent = (ViewGroup) getRootView().getParent(); final ViewGroup parent = (ViewGroup) binding.getRoot().getParent();
return (AppCompatActivity) parent.getContext(); return (AppCompatActivity) parent.getContext();
} }
@ -644,13 +577,14 @@ public class VideoPlayerImpl extends VideoPlayer
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, true); NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, true);
} }
@Override
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) { protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
super.onMetadataChanged(tag); super.onMetadataChanged(tag);
showHideKodiButton(); showHideKodiButton();
titleTextView.setText(tag.getMetadata().getName()); binding.titleTextView.setText(tag.getMetadata().getName());
channelTextView.setText(tag.getMetadata().getUploaderName()); binding.channelTextView.setText(tag.getMetadata().getUploaderName());
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false); NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
updateMetadata(); updateMetadata();
@ -668,7 +602,7 @@ public class VideoPlayerImpl extends VideoPlayer
public void onMuteUnmuteButtonClicked() { public void onMuteUnmuteButtonClicked() {
super.onMuteUnmuteButtonClicked(); super.onMuteUnmuteButtonClicked();
updatePlayback(); updatePlayback();
setMuteButton(muteButton, isMuted()); setMuteButton(binding.switchMute, isMuted());
} }
@Override @Override
@ -747,7 +681,7 @@ public class VideoPlayerImpl extends VideoPlayer
if (!isFullscreen) { if (!isFullscreen) {
// Apply window insets because Android will not do it when orientation changes // Apply window insets because Android will not do it when orientation changes
// from landscape to portrait (open vertical video to reproduce) // from landscape to portrait (open vertical video to reproduce)
getControlsRoot().setPadding(0, 0, 0, 0); getPlaybackControlRoot().setPadding(0, 0, 0, 0);
} else { } else {
// Android needs tens milliseconds to send new insets but a user is able to see // Android needs tens milliseconds to send new insets but a user is able to see
// how controls changes it's position from `0` to `nav bar height` padding. // how controls changes it's position from `0` to `nav bar height` padding.
@ -757,13 +691,14 @@ public class VideoPlayerImpl extends VideoPlayer
fragmentListener.onFullscreenStateChanged(isFullscreen()); fragmentListener.onFullscreenStateChanged(isFullscreen());
if (!isFullscreen()) { if (!isFullscreen()) {
titleTextView.setVisibility(View.GONE); binding.titleTextView.setVisibility(View.GONE);
channelTextView.setVisibility(View.GONE); binding.channelTextView.setVisibility(View.GONE);
playerCloseButton.setVisibility(videoPlayerSelected() ? View.VISIBLE : View.GONE); binding.playerCloseButton.setVisibility(videoPlayerSelected()
? View.VISIBLE : View.GONE);
} else { } else {
titleTextView.setVisibility(View.VISIBLE); binding.titleTextView.setVisibility(View.VISIBLE);
channelTextView.setVisibility(View.VISIBLE); binding.channelTextView.setVisibility(View.VISIBLE);
playerCloseButton.setVisibility(View.GONE); binding.playerCloseButton.setVisibility(View.GONE);
} }
setupScreenRotationButton(); setupScreenRotationButton();
} }
@ -771,34 +706,34 @@ public class VideoPlayerImpl extends VideoPlayer
@Override @Override
public void onClick(final View v) { public void onClick(final View v) {
super.onClick(v); super.onClick(v);
if (v.getId() == playPauseButton.getId()) { if (v.getId() == binding.playPauseButton.getId()) {
onPlayPause(); onPlayPause();
} else if (v.getId() == playPreviousButton.getId()) { } else if (v.getId() == binding.playPreviousButton.getId()) {
onPlayPrevious(); onPlayPrevious();
} else if (v.getId() == playNextButton.getId()) { } else if (v.getId() == binding.playNextButton.getId()) {
onPlayNext(); onPlayNext();
} else if (v.getId() == queueButton.getId()) { } else if (v.getId() == binding.queueButton.getId()) {
onQueueClicked(); onQueueClicked();
return; return;
} else if (v.getId() == repeatButton.getId()) { } else if (v.getId() == binding.repeatButton.getId()) {
onRepeatClicked(); onRepeatClicked();
return; return;
} else if (v.getId() == shuffleButton.getId()) { } else if (v.getId() == binding.shuffleButton.getId()) {
onShuffleClicked(); onShuffleClicked();
return; return;
} else if (v.getId() == moreOptionsButton.getId()) { } else if (v.getId() == binding.moreOptionsButton.getId()) {
onMoreOptionsClicked(); onMoreOptionsClicked();
} else if (v.getId() == shareButton.getId()) { } else if (v.getId() == binding.share.getId()) {
onShareClicked(); onShareClicked();
} else if (v.getId() == playWithKodi.getId()) { } else if (v.getId() == binding.playWithKodi.getId()) {
onPlayWithKodiClicked(); onPlayWithKodiClicked();
} else if (v.getId() == openInBrowser.getId()) { } else if (v.getId() == binding.openInBrowser.getId()) {
onOpenInBrowserClicked(); onOpenInBrowserClicked();
} else if (v.getId() == fullscreenButton.getId()) { } else if (v.getId() == binding.fullScreenButton.getId()) {
setRecovery(); setRecovery();
NavigationHelper.playOnMainPlayer(context, getPlayQueue(), true); NavigationHelper.playOnMainPlayer(context, getPlayQueue(), true);
return; return;
} else if (v.getId() == screenRotationButton.getId()) { } else if (v.getId() == binding.screenRotationButton.getId()) {
// Only if it's not a vertical video or vertical video but in landscape with locked // Only if it's not a vertical video or vertical video but in landscape with locked
// orientation a screen orientation can be changed automatically // orientation a screen orientation can be changed automatically
if (!isVerticalVideo if (!isVerticalVideo
@ -807,20 +742,22 @@ public class VideoPlayerImpl extends VideoPlayer
} else { } else {
toggleFullscreen(); toggleFullscreen();
} }
} else if (v.getId() == muteButton.getId()) { } else if (v.getId() == binding.switchMute.getId()) {
onMuteUnmuteButtonClicked(); onMuteUnmuteButtonClicked();
} else if (v.getId() == playerCloseButton.getId()) { } else if (v.getId() == binding.playerCloseButton.getId()) {
service.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER)); service.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER));
} }
if (getCurrentState() != STATE_COMPLETED) { if (getCurrentState() != STATE_COMPLETED) {
getControlsVisibilityHandler().removeCallbacksAndMessages(null); getControlsVisibilityHandler().removeCallbacksAndMessages(null);
showHideShadow(true, DEFAULT_CONTROLS_DURATION, 0); showHideShadow(true, DEFAULT_CONTROLS_DURATION, 0);
animateView(getControlsRoot(), true, DEFAULT_CONTROLS_DURATION, 0, () -> { animateView(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION, 0,
() -> {
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) { if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
if (v.getId() == playPauseButton.getId() if (v.getId() == binding.playPauseButton.getId()
// Hide controls in fullscreen immediately // Hide controls in fullscreen immediately
|| (v.getId() == screenRotationButton.getId() && isFullscreen)) { || (v.getId() == binding.screenRotationButton.getId()
&& isFullscreen)) {
hideControls(0, 0); hideControls(0, 0);
} else { } else {
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
@ -832,7 +769,7 @@ public class VideoPlayerImpl extends VideoPlayer
@Override @Override
public boolean onLongClick(final View v) { public boolean onLongClick(final View v) {
if (v.getId() == moreOptionsButton.getId() && isFullscreen()) { if (v.getId() == binding.moreOptionsButton.getId() && isFullscreen()) {
fragmentListener.onMoreOptionsLongClicked(); fragmentListener.onMoreOptionsLongClicked();
hideControls(0, 0); hideControls(0, 0);
hideSystemUIIfNeeded(); hideSystemUIIfNeeded();
@ -848,11 +785,11 @@ public class VideoPlayerImpl extends VideoPlayer
updatePlaybackButtons(); updatePlaybackButtons();
hideControls(0, 0); hideControls(0, 0);
queueLayout.requestFocus(); binding.playQueuePanel.requestFocus();
animateView(queueLayout, SLIDE_AND_ALPHA, true, animateView(binding.playQueuePanel, SLIDE_AND_ALPHA, true,
DEFAULT_CONTROLS_DURATION); DEFAULT_CONTROLS_DURATION);
itemsList.scrollToPosition(playQueue.getIndex()); binding.playQueue.scrollToPosition(playQueue.getIndex());
} }
public void onQueueClosed() { public void onQueueClosed() {
@ -860,14 +797,15 @@ public class VideoPlayerImpl extends VideoPlayer
return; return;
} }
animateView(queueLayout, SLIDE_AND_ALPHA, false, animateView(binding.playQueuePanel, SLIDE_AND_ALPHA, false,
DEFAULT_CONTROLS_DURATION, 0, () -> { DEFAULT_CONTROLS_DURATION, 0, () -> {
// Even when queueLayout is GONE it receives touch events // Even when queueLayout is GONE it receives touch events
// and ruins normal behavior of the app. This line fixes it // and ruins normal behavior of the app. This line fixes it
queueLayout.setTranslationY(-queueLayout.getHeight() * 5); binding.playQueuePanel
.setTranslationY(-binding.playQueuePanel.getHeight() * 5);
}); });
queueVisible = false; queueVisible = false;
playPauseButton.requestFocus(); binding.playPauseButton.requestFocus();
} }
private void onMoreOptionsClicked() { private void onMoreOptionsClicked() {
@ -875,18 +813,19 @@ public class VideoPlayerImpl extends VideoPlayer
Log.d(TAG, "onMoreOptionsClicked() called"); Log.d(TAG, "onMoreOptionsClicked() called");
} }
final boolean isMoreControlsVisible = secondaryControls.getVisibility() == View.VISIBLE; final boolean isMoreControlsVisible =
binding.secondaryControls.getVisibility() == View.VISIBLE;
animateRotation(moreOptionsButton, DEFAULT_CONTROLS_DURATION, animateRotation(binding.moreOptionsButton, DEFAULT_CONTROLS_DURATION,
isMoreControlsVisible ? 0 : 180); isMoreControlsVisible ? 0 : 180);
animateView(secondaryControls, SLIDE_AND_ALPHA, !isMoreControlsVisible, animateView(binding.secondaryControls, SLIDE_AND_ALPHA, !isMoreControlsVisible,
DEFAULT_CONTROLS_DURATION, 0, DEFAULT_CONTROLS_DURATION, 0,
() -> { () -> {
// Fix for a ripple effect on background drawable. // Fix for a ripple effect on background drawable.
// When view returns from GONE state it takes more milliseconds than returning // When view returns from GONE state it takes more milliseconds than returning
// from INVISIBLE state. And the delay makes ripple background end to fast // from INVISIBLE state. And the delay makes ripple background end to fast
if (isMoreControlsVisible) { if (isMoreControlsVisible) {
secondaryControls.setVisibility(View.INVISIBLE); binding.secondaryControls.setVisibility(View.INVISIBLE);
} }
}); });
showControls(DEFAULT_CONTROLS_DURATION); showControls(DEFAULT_CONTROLS_DURATION);
@ -896,7 +835,7 @@ public class VideoPlayerImpl extends VideoPlayer
// share video at the current time (youtube.com/watch?v=ID&t=SECONDS) // share video at the current time (youtube.com/watch?v=ID&t=SECONDS)
// Timestamp doesn't make sense in a live stream so drop it // Timestamp doesn't make sense in a live stream so drop it
final int ts = getPlaybackSeekBar().getProgress() / 1000; final int ts = playbackSeekBar.getProgress() / 1000;
final MediaSourceTag metadata = getCurrentMetadata(); final MediaSourceTag metadata = getCurrentMetadata();
String videoUrl = getVideoUrl(); String videoUrl = getVideoUrl();
if (!isLive() && ts >= 0 && metadata != null if (!isLive() && ts >= 0 && metadata != null
@ -938,17 +877,17 @@ public class VideoPlayerImpl extends VideoPlayer
// show kodi button if it supports the current service and it is enabled in settings // show kodi button if it supports the current service and it is enabled in settings
final boolean showKodiButton = playQueue != null && playQueue.getItem() != null final boolean showKodiButton = playQueue != null && playQueue.getItem() != null
&& KoreUtil.shouldShowPlayWithKodi(context, playQueue.getItem().getServiceId()); && KoreUtil.shouldShowPlayWithKodi(context, playQueue.getItem().getServiceId());
playWithKodi.setVisibility(videoPlayerSelected() && kodiEnabled && showKodiButton binding.playWithKodi.setVisibility(videoPlayerSelected() && kodiEnabled
? View.VISIBLE : View.GONE); && showKodiButton ? View.VISIBLE : View.GONE);
} }
private void setupScreenRotationButton() { private void setupScreenRotationButton() {
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service); final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
final boolean showButton = videoPlayerSelected() final boolean showButton = videoPlayerSelected()
&& (orientationLocked || isVerticalVideo || DeviceUtils.isTablet(service)); && (orientationLocked || isVerticalVideo || DeviceUtils.isTablet(service));
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE); binding.screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
screenRotationButton.setImageDrawable(AppCompatResources.getDrawable(service, isFullscreen() binding.screenRotationButton.setImageDrawable(AppCompatResources.getDrawable(service,
? R.drawable.ic_fullscreen_exit_white_24dp isFullscreen() ? R.drawable.ic_fullscreen_exit_white_24dp
: R.drawable.ic_fullscreen_white_24dp)); : R.drawable.ic_fullscreen_white_24dp));
} }
@ -1009,11 +948,12 @@ public class VideoPlayerImpl extends VideoPlayer
Log.d(TAG, "maxGestureLength = " + maxGestureLength); Log.d(TAG, "maxGestureLength = " + maxGestureLength);
} }
volumeProgressBar.setMax(maxGestureLength); binding.volumeProgressBar.setMax(maxGestureLength);
brightnessProgressBar.setMax(maxGestureLength); binding.brightnessProgressBar.setMax(maxGestureLength);
setInitialGestureValues(); setInitialGestureValues();
queueLayout.getLayoutParams().height = height - queueLayout.getTop(); binding.playQueuePanel.getLayoutParams().height = height
- binding.playQueuePanel.getTop();
} }
} }
@ -1073,7 +1013,8 @@ public class VideoPlayerImpl extends VideoPlayer
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
private void animatePlayButtons(final boolean show, final int duration) { private void animatePlayButtons(final boolean show, final int duration) {
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration); animateView(binding.playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, show,
duration);
boolean showQueueButtons = show; boolean showQueueButtons = show;
if (playQueue == null) { if (playQueue == null) {
@ -1082,19 +1023,18 @@ public class VideoPlayerImpl extends VideoPlayer
if (!showQueueButtons || playQueue.getIndex() > 0) { if (!showQueueButtons || playQueue.getIndex() > 0) {
animateView( animateView(
playPreviousButton, binding.playPreviousButton,
AnimationUtils.Type.SCALE_AND_ALPHA, AnimationUtils.Type.SCALE_AND_ALPHA,
showQueueButtons, showQueueButtons,
duration); duration);
} }
if (!showQueueButtons || playQueue.getIndex() + 1 < playQueue.getStreams().size()) { if (!showQueueButtons || playQueue.getIndex() + 1 < playQueue.getStreams().size()) {
animateView( animateView(
playNextButton, binding.playNextButton,
AnimationUtils.Type.SCALE_AND_ALPHA, AnimationUtils.Type.SCALE_AND_ALPHA,
showQueueButtons, showQueueButtons,
duration); duration);
} }
} }
@Override @Override
@ -1106,7 +1046,7 @@ public class VideoPlayerImpl extends VideoPlayer
@Override @Override
public void onBlocked() { public void onBlocked() {
super.onBlocked(); super.onBlocked();
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp); binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
animatePlayButtons(false, 100); animatePlayButtons(false, 100);
getRootView().setKeepScreenOn(false); getRootView().setKeepScreenOn(false);
@ -1126,11 +1066,12 @@ public class VideoPlayerImpl extends VideoPlayer
@Override @Override
public void onPlaying() { public void onPlaying() {
super.onPlaying(); super.onPlaying();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> { animateView(binding.playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false,
playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp); 80, 0, () -> {
binding.playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp);
animatePlayButtons(true, 200); animatePlayButtons(true, 200);
if (!queueVisible) { if (!queueVisible) {
playPauseButton.requestFocus(); binding.playPauseButton.requestFocus();
} }
}); });
@ -1144,11 +1085,13 @@ public class VideoPlayerImpl extends VideoPlayer
@Override @Override
public void onPaused() { public void onPaused() {
super.onPaused(); super.onPaused();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> { animateView(binding.playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA,
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp); false, 80, 0, () -> {
binding.playPauseButton
.setImageResource(R.drawable.ic_play_arrow_white_24dp);
animatePlayButtons(true, 200); animatePlayButtons(true, 200);
if (!queueVisible) { if (!queueVisible) {
playPauseButton.requestFocus(); binding.playPauseButton.requestFocus();
} }
}); });
@ -1177,8 +1120,9 @@ public class VideoPlayerImpl extends VideoPlayer
@Override @Override
public void onCompleted() { public void onCompleted() {
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, () -> { animateView(binding.playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false,
playPauseButton.setImageResource(R.drawable.ic_replay_white_24dp); 0, 0, () -> {
binding.playPauseButton.setImageResource(R.drawable.ic_replay_white_24dp);
animatePlayButtons(true, DEFAULT_CONTROLS_DURATION); animatePlayButtons(true, DEFAULT_CONTROLS_DURATION);
}); });
@ -1355,8 +1299,8 @@ public class VideoPlayerImpl extends VideoPlayer
if (getAudioReactor() != null) { if (getAudioReactor() != null) {
final float currentVolumeNormalized = (float) getAudioReactor() final float currentVolumeNormalized = (float) getAudioReactor()
.getVolume() / getAudioReactor().getMaxVolume(); .getVolume() / getAudioReactor().getMaxVolume();
volumeProgressBar.setProgress( binding.volumeProgressBar.setProgress(
(int) (volumeProgressBar.getMax() * currentVolumeNormalized)); (int) (binding.volumeProgressBar.getMax() * currentVolumeNormalized));
} }
} }
@ -1453,14 +1397,15 @@ public class VideoPlayerImpl extends VideoPlayer
getControlsVisibilityHandler().removeCallbacksAndMessages(null); getControlsVisibilityHandler().removeCallbacksAndMessages(null);
getControlsVisibilityHandler().postDelayed(() -> { getControlsVisibilityHandler().postDelayed(() -> {
showHideShadow(false, duration, 0); showHideShadow(false, duration, 0);
animateView(getControlsRoot(), false, duration, 0, this::hideSystemUIIfNeeded); animateView(binding.playbackControlRoot, false, duration, 0,
this::hideSystemUIIfNeeded);
}, delay }, delay
); );
} }
@Override @Override
public void safeHideControls(final long duration, final long delay) { public void safeHideControls(final long duration, final long delay) {
if (getControlsRoot().isInTouchMode()) { if (binding.playbackControlRoot.isInTouchMode()) {
hideControls(duration, delay); hideControls(duration, delay);
} }
} }
@ -1474,12 +1419,12 @@ public class VideoPlayerImpl extends VideoPlayer
final boolean showNext = playQueue.getIndex() + 1 != playQueue.getStreams().size(); final boolean showNext = playQueue.getIndex() + 1 != playQueue.getStreams().size();
final boolean showQueue = playQueue.getStreams().size() > 1 && !popupPlayerSelected(); final boolean showQueue = playQueue.getStreams().size() > 1 && !popupPlayerSelected();
playPreviousButton.setVisibility(showPrev ? View.VISIBLE : View.INVISIBLE); binding.playPreviousButton.setVisibility(showPrev ? View.VISIBLE : View.INVISIBLE);
playPreviousButton.setAlpha(showPrev ? 1.0f : 0.0f); binding.playPreviousButton.setAlpha(showPrev ? 1.0f : 0.0f);
playNextButton.setVisibility(showNext ? View.VISIBLE : View.INVISIBLE); binding.playNextButton.setVisibility(showNext ? View.VISIBLE : View.INVISIBLE);
playNextButton.setAlpha(showNext ? 1.0f : 0.0f); binding.playNextButton.setAlpha(showNext ? 1.0f : 0.0f);
queueButton.setVisibility(showQueue ? View.VISIBLE : View.GONE); binding.queueButton.setVisibility(showQueue ? View.VISIBLE : View.GONE);
queueButton.setAlpha(showQueue ? 1.0f : 0.0f); binding.queueButton.setAlpha(showQueue ? 1.0f : 0.0f);
} }
private void showSystemUIPartially() { private void showSystemUIPartially() {
@ -1524,15 +1469,12 @@ public class VideoPlayerImpl extends VideoPlayer
} }
private void updatePlaybackButtons() { private void updatePlaybackButtons() {
if (repeatButton == null if (binding == null || simpleExoPlayer == null || playQueue == null) {
|| shuffleButton == null
|| simpleExoPlayer == null
|| playQueue == null) {
return; return;
} }
setRepeatModeButton(repeatButton, getRepeatMode()); setRepeatModeButton(binding.repeatButton, getRepeatMode());
setShuffleButton(shuffleButton, playQueue.isShuffled()); setShuffleButton(binding.shuffleButton, playQueue.isShuffled());
} }
public void checkLandscape() { public void checkLandscape() {
@ -1553,19 +1495,19 @@ public class VideoPlayerImpl extends VideoPlayer
} }
private void buildQueue() { private void buildQueue() {
itemsList.setAdapter(playQueueAdapter); binding.playQueue.setAdapter(playQueueAdapter);
itemsList.setClickable(true); binding.playQueue.setClickable(true);
itemsList.setLongClickable(true); binding.playQueue.setLongClickable(true);
itemsList.clearOnScrollListeners(); binding.playQueue.clearOnScrollListeners();
itemsList.addOnScrollListener(getQueueScrollListener()); binding.playQueue.addOnScrollListener(getQueueScrollListener());
itemTouchHelper = new ItemTouchHelper(getItemTouchCallback()); itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
itemTouchHelper.attachToRecyclerView(itemsList); itemTouchHelper.attachToRecyclerView(binding.playQueue);
playQueueAdapter.setSelectedListener(getOnSelectedListener()); playQueueAdapter.setSelectedListener(getOnSelectedListener());
itemsListCloseButton.setOnClickListener(view -> onQueueClosed()); binding.playQueueClose.setOnClickListener(view -> onQueueClosed());
} }
public void useVideoSource(final boolean video) { public void useVideoSource(final boolean video) {
@ -1589,8 +1531,8 @@ public class VideoPlayerImpl extends VideoPlayer
public void onScrolledDown(final RecyclerView recyclerView) { public void onScrolledDown(final RecyclerView recyclerView) {
if (playQueue != null && !playQueue.isComplete()) { if (playQueue != null && !playQueue.isComplete()) {
playQueue.fetch(); playQueue.fetch();
} else if (itemsList != null) { } else if (binding != null) {
itemsList.clearOnScrollListeners(); binding.playQueue.clearOnScrollListeners();
} }
} }
}; };
@ -1682,8 +1624,8 @@ public class VideoPlayerImpl extends VideoPlayer
checkPopupPositionBounds(); checkPopupPositionBounds();
getLoadingPanel().setMinimumWidth(popupLayoutParams.width); binding.loadingPanel.setMinimumWidth(popupLayoutParams.width);
getLoadingPanel().setMinimumHeight(popupLayoutParams.height); binding.loadingPanel.setMinimumHeight(popupLayoutParams.height);
service.removeViewFromParent(); service.removeViewFromParent();
windowManager.addView(getRootView(), popupLayoutParams); windowManager.addView(getRootView(), popupLayoutParams);
@ -1933,10 +1875,9 @@ public class VideoPlayerImpl extends VideoPlayer
} }
private boolean popupHasParent() { private boolean popupHasParent() {
final View root = getRootView(); return binding != null
return root != null && binding.getRoot().getLayoutParams() instanceof WindowManager.LayoutParams
&& root.getLayoutParams() instanceof WindowManager.LayoutParams && binding.getRoot().getParent() != null;
&& root.getParent() != null;
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -1949,9 +1890,9 @@ public class VideoPlayerImpl extends VideoPlayer
// Apply window insets because Android will not do it when orientation changes // Apply window insets because Android will not do it when orientation changes
// from landscape to portrait // from landscape to portrait
if (!isFullscreen) { if (!isFullscreen) {
getControlsRoot().setPadding(0, 0, 0, 0); binding.playbackControlRoot.setPadding(0, 0, 0, 0);
} }
queueLayout.setPadding(0, 0, 0, 0); binding.playQueuePanel.setPadding(0, 0, 0, 0);
updateQueue(); updateQueue();
updateMetadata(); updateMetadata();
updatePlayback(); updatePlayback();
@ -2050,31 +1991,31 @@ public class VideoPlayerImpl extends VideoPlayer
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
public RelativeLayout getVolumeRelativeLayout() { public RelativeLayout getVolumeRelativeLayout() {
return volumeRelativeLayout; return binding.volumeRelativeLayout;
} }
public ProgressBar getVolumeProgressBar() { public ProgressBar getVolumeProgressBar() {
return volumeProgressBar; return binding.volumeProgressBar;
} }
public ImageView getVolumeImageView() { public ImageView getVolumeImageView() {
return volumeImageView; return binding.volumeImageView;
} }
public RelativeLayout getBrightnessRelativeLayout() { public RelativeLayout getBrightnessRelativeLayout() {
return brightnessRelativeLayout; return binding.brightnessRelativeLayout;
} }
public ProgressBar getBrightnessProgressBar() { public ProgressBar getBrightnessProgressBar() {
return brightnessProgressBar; return binding.brightnessProgressBar;
} }
public ImageView getBrightnessImageView() { public ImageView getBrightnessImageView() {
return brightnessImageView; return binding.brightnessImageView;
} }
public ImageButton getPlayPauseButton() { public ImageButton getPlayPauseButton() {
return playPauseButton; return binding.playPauseButton;
} }
public int getMaxGestureLength() { public int getMaxGestureLength() {
@ -2082,7 +2023,7 @@ public class VideoPlayerImpl extends VideoPlayer
} }
public TextView getResizingIndicator() { public TextView getResizingIndicator() {
return resizingIndicator; return binding.resizingIndicator;
} }
public GestureDetector getGestureDetector() { public GestureDetector getGestureDetector() {
@ -2125,8 +2066,8 @@ public class VideoPlayerImpl extends VideoPlayer
return closeOverlayButton; return closeOverlayButton;
} }
public View getClosingOverlayView() { public View getClosingOverlay() {
return closingOverlayView; return binding.closingOverlay;
} }
public boolean isVerticalVideo() { public boolean isVerticalVideo() {

View File

@ -123,7 +123,7 @@ public class PlayerGestureListener
} }
} else /* MainPlayer.PlayerType.POPUP */ { } else /* MainPlayer.PlayerType.POPUP */ {
final View closingOverlayView = playerImpl.getClosingOverlayView(); final View closingOverlayView = playerImpl.getClosingOverlay();
if (playerImpl.isInsideClosingRadius(movingEvent)) { if (playerImpl.isInsideClosingRadius(movingEvent)) {
if (closingOverlayView.getVisibility() == View.GONE) { if (closingOverlayView.getVisibility() == View.GONE) {
animateView(closingOverlayView, true, 250); animateView(closingOverlayView, true, 250);
@ -240,7 +240,7 @@ public class PlayerGestureListener
if (playerImpl.isInsideClosingRadius(event)) { if (playerImpl.isInsideClosingRadius(event)) {
playerImpl.closePopup(); playerImpl.closePopup();
} else { } else {
animateView(playerImpl.getClosingOverlayView(), false, 0); animateView(playerImpl.getClosingOverlay(), false, 0);
if (!playerImpl.isPopupClosing) { if (!playerImpl.isPopupClosing) {
animateView(playerImpl.getCloseOverlayButton(), false, 200); animateView(playerImpl.getCloseOverlayButton(), false, 200);