|
|
@ -3,14 +3,11 @@ package awais.instagrabber.customviews; |
|
|
|
import android.content.Context; |
|
|
|
import android.graphics.drawable.Animatable; |
|
|
|
import android.net.Uri; |
|
|
|
import android.os.Handler; |
|
|
|
import android.os.Looper; |
|
|
|
import android.util.Log; |
|
|
|
import android.view.View; |
|
|
|
|
|
|
|
import androidx.annotation.NonNull; |
|
|
|
import androidx.appcompat.view.ContextThemeWrapper; |
|
|
|
import androidx.appcompat.widget.AppCompatTextView; |
|
|
|
import androidx.appcompat.widget.PopupMenu; |
|
|
|
|
|
|
|
import com.facebook.drawee.backends.pipeline.Fresco; |
|
|
@ -21,103 +18,95 @@ import com.facebook.imagepipeline.request.ImageRequest; |
|
|
|
import com.facebook.imagepipeline.request.ImageRequestBuilder; |
|
|
|
import com.google.android.exoplayer2.ExoPlaybackException; |
|
|
|
import com.google.android.exoplayer2.MediaItem; |
|
|
|
import com.google.android.exoplayer2.PlaybackParameters; |
|
|
|
import com.google.android.exoplayer2.Player; |
|
|
|
import com.google.android.exoplayer2.SimpleExoPlayer; |
|
|
|
import com.google.android.exoplayer2.audio.AudioListener; |
|
|
|
import com.google.android.exoplayer2.source.ProgressiveMediaSource; |
|
|
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; |
|
|
|
import com.google.android.material.slider.LabelFormatter; |
|
|
|
import com.google.android.material.slider.Slider; |
|
|
|
import com.google.android.material.button.MaterialButton; |
|
|
|
|
|
|
|
import awais.instagrabber.R; |
|
|
|
import awais.instagrabber.databinding.LayoutExoCustomControlsBinding; |
|
|
|
import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding; |
|
|
|
import awais.instagrabber.utils.TextUtils; |
|
|
|
|
|
|
|
import static com.google.android.exoplayer2.C.TIME_UNSET; |
|
|
|
import static com.google.android.exoplayer2.Player.STATE_ENDED; |
|
|
|
import static com.google.android.exoplayer2.Player.STATE_IDLE; |
|
|
|
import static com.google.android.exoplayer2.Player.STATE_READY; |
|
|
|
|
|
|
|
public class VideoPlayerViewHelper implements Player.EventListener { |
|
|
|
private static final String TAG = "VideoPlayerViewHelper"; |
|
|
|
private static final long INITIAL_DELAY = 0; |
|
|
|
private static final long RECURRING_DELAY = 60; |
|
|
|
// private static final long INITIAL_DELAY = 0; |
|
|
|
// private static final long RECURRING_DELAY = 60; |
|
|
|
|
|
|
|
private final Context context; |
|
|
|
private final awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding binding; |
|
|
|
private final LayoutVideoPlayerWithThumbnailBinding binding; |
|
|
|
private final float initialVolume; |
|
|
|
private final float thumbnailAspectRatio; |
|
|
|
private final String thumbnailUrl; |
|
|
|
private final boolean loadPlayerOnClick; |
|
|
|
private final awais.instagrabber.databinding.LayoutExoCustomControlsBinding controlsBinding; |
|
|
|
// private final LayoutExoCustomControlsBinding controlsBinding; |
|
|
|
private final VideoPlayerCallback videoPlayerCallback; |
|
|
|
private final String videoUrl; |
|
|
|
private final DefaultDataSourceFactory dataSourceFactory; |
|
|
|
private SimpleExoPlayer player; |
|
|
|
private PopupMenu speedPopup; |
|
|
|
private PositionCheckRunnable positionChecker; |
|
|
|
private Handler positionUpdateHandler; |
|
|
|
|
|
|
|
private final Player.EventListener listener = new Player.EventListener() { |
|
|
|
@Override |
|
|
|
public void onPlaybackStateChanged(final int state) { |
|
|
|
switch (state) { |
|
|
|
case Player.STATE_BUFFERING: |
|
|
|
case STATE_IDLE: |
|
|
|
case STATE_ENDED: |
|
|
|
positionUpdateHandler.removeCallbacks(positionChecker); |
|
|
|
return; |
|
|
|
case STATE_READY: |
|
|
|
setupTimeline(); |
|
|
|
positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) { |
|
|
|
updatePlayPauseDrawable(playWhenReady); |
|
|
|
if (positionUpdateHandler == null || positionChecker == null) return; |
|
|
|
if (playWhenReady) { |
|
|
|
positionUpdateHandler.removeCallbacks(positionChecker); |
|
|
|
positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
// private PositionCheckRunnable positionChecker; |
|
|
|
// private Handler positionUpdateHandler; |
|
|
|
|
|
|
|
// private final Player.EventListener listener = new Player.EventListener() { |
|
|
|
// @Override |
|
|
|
// public void onPlaybackStateChanged(final int state) { |
|
|
|
// // switch (state) { |
|
|
|
// // case Player.STATE_BUFFERING: |
|
|
|
// // case STATE_IDLE: |
|
|
|
// // case STATE_ENDED: |
|
|
|
// // positionUpdateHandler.removeCallbacks(positionChecker); |
|
|
|
// // return; |
|
|
|
// // case STATE_READY: |
|
|
|
// // setupTimeline(); |
|
|
|
// // positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY); |
|
|
|
// // break; |
|
|
|
// // } |
|
|
|
// } |
|
|
|
// |
|
|
|
// @Override |
|
|
|
// public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) { |
|
|
|
// // updatePlayPauseDrawable(playWhenReady); |
|
|
|
// // if (positionUpdateHandler == null || positionChecker == null) return; |
|
|
|
// // if (playWhenReady) { |
|
|
|
// // positionUpdateHandler.removeCallbacks(positionChecker); |
|
|
|
// // positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY); |
|
|
|
// // } |
|
|
|
// } |
|
|
|
// }; |
|
|
|
private final AudioListener audioListener = new AudioListener() { |
|
|
|
@Override |
|
|
|
public void onVolumeChanged(final float volume) { |
|
|
|
updateMuteIcon(volume); |
|
|
|
} |
|
|
|
}; |
|
|
|
private final Slider.OnChangeListener onChangeListener = (slider, value, fromUser) -> { |
|
|
|
if (!fromUser) return; |
|
|
|
long actualValue = (long) value; |
|
|
|
if (actualValue < 0) { |
|
|
|
actualValue = 0; |
|
|
|
} else if (actualValue > player.getDuration()) { |
|
|
|
actualValue = player.getDuration(); |
|
|
|
} |
|
|
|
player.seekTo(actualValue); |
|
|
|
}; |
|
|
|
private final View.OnClickListener onClickListener = v -> player.setPlayWhenReady(!player.getPlayWhenReady()); |
|
|
|
private final LabelFormatter labelFormatter = value -> TextUtils.millisToTimeString((long) value); |
|
|
|
// private final Slider.OnChangeListener onChangeListener = (slider, value, fromUser) -> { |
|
|
|
// if (!fromUser) return; |
|
|
|
// long actualValue = (long) value; |
|
|
|
// if (actualValue < 0) { |
|
|
|
// actualValue = 0; |
|
|
|
// } else if (actualValue > player.getDuration()) { |
|
|
|
// actualValue = player.getDuration(); |
|
|
|
// } |
|
|
|
// player.seekTo(actualValue); |
|
|
|
// }; |
|
|
|
// private final View.OnClickListener onClickListener = v -> player.setPlayWhenReady(!player.getPlayWhenReady()); |
|
|
|
// // private final LabelFormatter labelFormatter = value -> TextUtils.millisToTimeString((long) value); |
|
|
|
private final View.OnClickListener muteOnClickListener = v -> toggleMute(); |
|
|
|
private final View.OnClickListener rewOnClickListener = v -> { |
|
|
|
final long positionMs = player.getCurrentPosition() - 5000; |
|
|
|
player.seekTo(positionMs < 0 ? 0 : positionMs); |
|
|
|
}; |
|
|
|
private final View.OnClickListener ffOnClickListener = v -> { |
|
|
|
long positionMs = player.getCurrentPosition() + 5000; |
|
|
|
long duration = player.getDuration(); |
|
|
|
if (duration == TIME_UNSET) { |
|
|
|
duration = 0; |
|
|
|
} |
|
|
|
player.seekTo(Math.min(positionMs, duration)); |
|
|
|
}; |
|
|
|
private final View.OnClickListener showMenu = this::showMenu; |
|
|
|
private MaterialButton mute; |
|
|
|
// private final View.OnClickListener rewOnClickListener = v -> { |
|
|
|
// final long positionMs = player.getCurrentPosition() - 5000; |
|
|
|
// player.seekTo(positionMs < 0 ? 0 : positionMs); |
|
|
|
// }; |
|
|
|
// private final View.OnClickListener ffOnClickListener = v -> { |
|
|
|
// long positionMs = player.getCurrentPosition() + 5000; |
|
|
|
// long duration = player.getDuration(); |
|
|
|
// if (duration == TIME_UNSET) { |
|
|
|
// duration = 0; |
|
|
|
// } |
|
|
|
// player.seekTo(Math.min(positionMs, duration)); |
|
|
|
// }; |
|
|
|
// private final View.OnClickListener showMenu = this::showMenu; |
|
|
|
|
|
|
|
public VideoPlayerViewHelper(@NonNull final Context context, |
|
|
|
@NonNull final LayoutVideoPlayerWithThumbnailBinding binding, |
|
|
@ -126,7 +115,7 @@ public class VideoPlayerViewHelper implements Player.EventListener { |
|
|
|
final float thumbnailAspectRatio, |
|
|
|
final String thumbnailUrl, |
|
|
|
final boolean loadPlayerOnClick, |
|
|
|
final LayoutExoCustomControlsBinding controlsBinding, |
|
|
|
// final LayoutExoCustomControlsBinding controlsBinding, |
|
|
|
final VideoPlayerCallback videoPlayerCallback) { |
|
|
|
this.context = context; |
|
|
|
this.binding = binding; |
|
|
@ -134,7 +123,7 @@ public class VideoPlayerViewHelper implements Player.EventListener { |
|
|
|
this.thumbnailAspectRatio = thumbnailAspectRatio; |
|
|
|
this.thumbnailUrl = thumbnailUrl; |
|
|
|
this.loadPlayerOnClick = loadPlayerOnClick; |
|
|
|
this.controlsBinding = controlsBinding; |
|
|
|
// this.controlsBinding = controlsBinding; |
|
|
|
this.videoPlayerCallback = videoPlayerCallback; |
|
|
|
this.videoUrl = videoUrl; |
|
|
|
this.dataSourceFactory = new DefaultDataSourceFactory(binding.getRoot().getContext(), "instagram"); |
|
|
@ -151,7 +140,7 @@ public class VideoPlayerViewHelper implements Player.EventListener { |
|
|
|
} |
|
|
|
}); |
|
|
|
setThumbnail(); |
|
|
|
setupControls(); |
|
|
|
// setupControls(); |
|
|
|
} |
|
|
|
|
|
|
|
private void setThumbnail() { |
|
|
@ -200,12 +189,13 @@ public class VideoPlayerViewHelper implements Player.EventListener { |
|
|
|
player = new SimpleExoPlayer.Builder(context) |
|
|
|
.setLooper(Looper.getMainLooper()) |
|
|
|
.build(); |
|
|
|
positionUpdateHandler = new Handler(); |
|
|
|
positionChecker = new PositionCheckRunnable(positionUpdateHandler, |
|
|
|
player, |
|
|
|
controlsBinding.timeline, |
|
|
|
controlsBinding.fromTime); |
|
|
|
// positionUpdateHandler = new Handler(); |
|
|
|
// positionChecker = new PositionCheckRunnable(positionUpdateHandler, |
|
|
|
// player, |
|
|
|
// controlsBinding.timeline, |
|
|
|
// controlsBinding.fromTime); |
|
|
|
player.addListener(this); |
|
|
|
player.addAudioListener(audioListener); |
|
|
|
player.setVolume(initialVolume); |
|
|
|
player.setPlayWhenReady(true); |
|
|
|
player.setRepeatMode(Player.REPEAT_MODE_ALL); |
|
|
@ -213,124 +203,134 @@ public class VideoPlayerViewHelper implements Player.EventListener { |
|
|
|
final MediaItem mediaItem = MediaItem.fromUri(videoUrl); |
|
|
|
final ProgressiveMediaSource mediaSource = sourceFactory.createMediaSource(mediaItem); |
|
|
|
player.setMediaSource(mediaSource); |
|
|
|
setupControls(); |
|
|
|
// setupControls(); |
|
|
|
player.prepare(); |
|
|
|
binding.playerView.setPlayer(player); |
|
|
|
binding.playerView.setShowFastForwardButton(false); |
|
|
|
binding.playerView.setShowRewindButton(false); |
|
|
|
// binding.controls.setPlayer(player); |
|
|
|
mute = binding.playerView.findViewById(R.id.mute); |
|
|
|
// mute = binding.controls.findViewById(R.id.mute); |
|
|
|
if (mute != null) { |
|
|
|
mute.setOnClickListener(muteOnClickListener); |
|
|
|
} |
|
|
|
|
|
|
|
private void setupControls() { |
|
|
|
if (controlsBinding == null) return; |
|
|
|
binding.playerView.setUseController(false); |
|
|
|
if (player == null) { |
|
|
|
enableControls(false); |
|
|
|
// controlsBinding.playPause.setEnabled(true); |
|
|
|
// controlsBinding.playPause.setOnClickListener(new NoPlayerPlayPauseClickListener(binding.thumbnailParent)); |
|
|
|
return; |
|
|
|
} |
|
|
|
enableControls(true); |
|
|
|
updatePlayPauseDrawable(player.getPlayWhenReady()); |
|
|
|
updateMuteIcon(player.getVolume()); |
|
|
|
player.addListener(listener); |
|
|
|
player.addAudioListener(audioListener); |
|
|
|
controlsBinding.timeline.addOnChangeListener(onChangeListener); |
|
|
|
controlsBinding.timeline.setLabelFormatter(labelFormatter); |
|
|
|
controlsBinding.playPause.setOnClickListener(onClickListener); |
|
|
|
controlsBinding.mute.setOnClickListener(muteOnClickListener); |
|
|
|
controlsBinding.rewWithAmount.setOnClickListener(rewOnClickListener); |
|
|
|
controlsBinding.ffWithAmount.setOnClickListener(ffOnClickListener); |
|
|
|
controlsBinding.speed.setOnClickListener(showMenu); |
|
|
|
} |
|
|
|
|
|
|
|
private void setupTimeline() { |
|
|
|
final long duration = player.getDuration(); |
|
|
|
controlsBinding.timeline.setEnabled(true); |
|
|
|
controlsBinding.timeline.setValueFrom(0); |
|
|
|
controlsBinding.timeline.setValueTo(duration); |
|
|
|
controlsBinding.fromTime.setText(TextUtils.millisToTimeString(0)); |
|
|
|
controlsBinding.toTime.setText(TextUtils.millisToTimeString(duration)); |
|
|
|
} |
|
|
|
// private void setupControls() { |
|
|
|
// if (controlsBinding == null) return; |
|
|
|
// // binding.playerView.setUseController(false); |
|
|
|
// if (player == null) { |
|
|
|
// // enableControls(false); |
|
|
|
// // controlsBinding.playPause.setEnabled(true); |
|
|
|
// // controlsBinding.playPause.setOnClickListener(new NoPlayerPlayPauseClickListener(binding.thumbnailParent)); |
|
|
|
// return; |
|
|
|
// } |
|
|
|
// // enableControls(true); |
|
|
|
// // updatePlayPauseDrawable(player.getPlayWhenReady()); |
|
|
|
// // updateMuteIcon(player.getVolume()); |
|
|
|
// player.addListener(listener); |
|
|
|
// // player.addAudioListener(audioListener); |
|
|
|
// // controlsBinding.timeline.addOnChangeListener(onChangeListener); |
|
|
|
// // controlsBinding.timeline.setLabelFormatter(labelFormatter); |
|
|
|
// // controlsBinding.playPause.setOnClickListener(onClickListener); |
|
|
|
// // controlsBinding.mute.setOnClickListener(muteOnClickListener); |
|
|
|
// // controlsBinding.rewWithAmount.setOnClickListener(rewOnClickListener); |
|
|
|
// // controlsBinding.ffWithAmount.setOnClickListener(ffOnClickListener); |
|
|
|
// // controlsBinding.speed.setOnClickListener(showMenu); |
|
|
|
// } |
|
|
|
|
|
|
|
private void enableControls(final boolean enable) { |
|
|
|
controlsBinding.speed.setEnabled(enable); |
|
|
|
controlsBinding.speed.setClickable(enable); |
|
|
|
controlsBinding.mute.setEnabled(enable); |
|
|
|
controlsBinding.mute.setClickable(enable); |
|
|
|
controlsBinding.ffWithAmount.setEnabled(enable); |
|
|
|
controlsBinding.ffWithAmount.setClickable(enable); |
|
|
|
controlsBinding.rewWithAmount.setEnabled(enable); |
|
|
|
controlsBinding.rewWithAmount.setClickable(enable); |
|
|
|
controlsBinding.fromTime.setEnabled(enable); |
|
|
|
controlsBinding.toTime.setEnabled(enable); |
|
|
|
controlsBinding.playPause.setEnabled(enable); |
|
|
|
controlsBinding.playPause.setClickable(enable); |
|
|
|
controlsBinding.timeline.setEnabled(enable); |
|
|
|
} |
|
|
|
// private void setupTimeline() { |
|
|
|
// final long duration = player.getDuration(); |
|
|
|
// controlsBinding.timeline.setEnabled(true); |
|
|
|
// controlsBinding.timeline.setValueFrom(0); |
|
|
|
// controlsBinding.timeline.setValueTo(duration); |
|
|
|
// controlsBinding.fromTime.setText(TextUtils.millisToTimeString(0)); |
|
|
|
// controlsBinding.toTime.setText(TextUtils.millisToTimeString(duration)); |
|
|
|
// } |
|
|
|
|
|
|
|
public void showMenu(View anchor) { |
|
|
|
PopupMenu popup = getPopupMenu(anchor); |
|
|
|
popup.show(); |
|
|
|
} |
|
|
|
// private void enableControls(final boolean enable) { |
|
|
|
// controlsBinding.speed.setEnabled(enable); |
|
|
|
// controlsBinding.speed.setClickable(enable); |
|
|
|
// controlsBinding.mute.setEnabled(enable); |
|
|
|
// controlsBinding.mute.setClickable(enable); |
|
|
|
// controlsBinding.ffWithAmount.setEnabled(enable); |
|
|
|
// controlsBinding.ffWithAmount.setClickable(enable); |
|
|
|
// controlsBinding.rewWithAmount.setEnabled(enable); |
|
|
|
// controlsBinding.rewWithAmount.setClickable(enable); |
|
|
|
// // controlsBinding.fromTime.setEnabled(enable); |
|
|
|
// // controlsBinding.toTime.setEnabled(enable); |
|
|
|
// controlsBinding.playPause.setEnabled(enable); |
|
|
|
// controlsBinding.playPause.setClickable(enable); |
|
|
|
// // controlsBinding.timeline.setEnabled(enable); |
|
|
|
// } |
|
|
|
|
|
|
|
@NonNull |
|
|
|
private PopupMenu getPopupMenu(final View anchor) { |
|
|
|
if (speedPopup != null) { |
|
|
|
return speedPopup; |
|
|
|
} |
|
|
|
final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle); |
|
|
|
// final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_PopupMenu_Exoplayer); |
|
|
|
speedPopup = new PopupMenu(themeWrapper, anchor); |
|
|
|
speedPopup.getMenuInflater().inflate(R.menu.speed_menu, speedPopup.getMenu()); |
|
|
|
speedPopup.setOnMenuItemClickListener(item -> { |
|
|
|
float nextSpeed; |
|
|
|
int textResId; |
|
|
|
int itemId = item.getItemId(); |
|
|
|
if (itemId == R.id.pt_two_five_x) { |
|
|
|
nextSpeed = 0.25f; |
|
|
|
textResId = R.string.pt_two_five_x; |
|
|
|
} else if (itemId == R.id.pt_five_x) { |
|
|
|
nextSpeed = 0.5f; |
|
|
|
textResId = R.string.pt_five_x; |
|
|
|
} else if (itemId == R.id.pt_seven_five_x) { |
|
|
|
nextSpeed = 0.75f; |
|
|
|
textResId = R.string.pt_seven_five_x; |
|
|
|
} else if (itemId == R.id.one_x) { |
|
|
|
nextSpeed = 1f; |
|
|
|
textResId = R.string.one_x; |
|
|
|
} else if (itemId == R.id.one_pt_two_five_x) { |
|
|
|
nextSpeed = 1.25f; |
|
|
|
textResId = R.string.one_pt_two_five_x; |
|
|
|
} else if (itemId == R.id.one_pt_five_x) { |
|
|
|
nextSpeed = 1.5f; |
|
|
|
textResId = R.string.one_pt_five_x; |
|
|
|
} else if (itemId == R.id.two_x) { |
|
|
|
nextSpeed = 2f; |
|
|
|
textResId = R.string.two_x; |
|
|
|
} else { |
|
|
|
nextSpeed = 1; |
|
|
|
textResId = R.string.one_x; |
|
|
|
} |
|
|
|
player.setPlaybackParameters(new PlaybackParameters(nextSpeed)); |
|
|
|
controlsBinding.speed.setText(textResId); |
|
|
|
return true; |
|
|
|
}); |
|
|
|
return speedPopup; |
|
|
|
} |
|
|
|
// public void showMenu(View anchor) { |
|
|
|
// PopupMenu popup = getPopupMenu(anchor); |
|
|
|
// popup.show(); |
|
|
|
// } |
|
|
|
|
|
|
|
// @NonNull |
|
|
|
// private PopupMenu getPopupMenu(final View anchor) { |
|
|
|
// if (speedPopup != null) { |
|
|
|
// return speedPopup; |
|
|
|
// } |
|
|
|
// final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle); |
|
|
|
// // final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_PopupMenu_Exoplayer); |
|
|
|
// speedPopup = new PopupMenu(themeWrapper, anchor); |
|
|
|
// speedPopup.getMenuInflater().inflate(R.menu.speed_menu, speedPopup.getMenu()); |
|
|
|
// speedPopup.setOnMenuItemClickListener(item -> { |
|
|
|
// float nextSpeed; |
|
|
|
// int textResId; |
|
|
|
// int itemId = item.getItemId(); |
|
|
|
// if (itemId == R.id.pt_two_five_x) { |
|
|
|
// nextSpeed = 0.25f; |
|
|
|
// textResId = R.string.pt_two_five_x; |
|
|
|
// } else if (itemId == R.id.pt_five_x) { |
|
|
|
// nextSpeed = 0.5f; |
|
|
|
// textResId = R.string.pt_five_x; |
|
|
|
// } else if (itemId == R.id.pt_seven_five_x) { |
|
|
|
// nextSpeed = 0.75f; |
|
|
|
// textResId = R.string.pt_seven_five_x; |
|
|
|
// } else if (itemId == R.id.one_x) { |
|
|
|
// nextSpeed = 1f; |
|
|
|
// textResId = R.string.one_x; |
|
|
|
// } else if (itemId == R.id.one_pt_two_five_x) { |
|
|
|
// nextSpeed = 1.25f; |
|
|
|
// textResId = R.string.one_pt_two_five_x; |
|
|
|
// } else if (itemId == R.id.one_pt_five_x) { |
|
|
|
// nextSpeed = 1.5f; |
|
|
|
// textResId = R.string.one_pt_five_x; |
|
|
|
// } else if (itemId == R.id.two_x) { |
|
|
|
// nextSpeed = 2f; |
|
|
|
// textResId = R.string.two_x; |
|
|
|
// } else { |
|
|
|
// nextSpeed = 1; |
|
|
|
// textResId = R.string.one_x; |
|
|
|
// } |
|
|
|
// player.setPlaybackParameters(new PlaybackParameters(nextSpeed)); |
|
|
|
// controlsBinding.speed.setText(textResId); |
|
|
|
// return true; |
|
|
|
// }); |
|
|
|
// return speedPopup; |
|
|
|
// } |
|
|
|
|
|
|
|
private void updateMuteIcon(final float volume) { |
|
|
|
if (mute == null) return; |
|
|
|
if (volume == 0) { |
|
|
|
controlsBinding.mute.setIconResource(R.drawable.ic_volume_off_24_states); |
|
|
|
mute.setIconResource(R.drawable.ic_volume_off_24_states); |
|
|
|
return; |
|
|
|
} |
|
|
|
controlsBinding.mute.setIconResource(R.drawable.ic_volume_up_24_states); |
|
|
|
mute.setIconResource(R.drawable.ic_volume_up_24_states); |
|
|
|
} |
|
|
|
|
|
|
|
private void updatePlayPauseDrawable(final boolean playWhenReady) { |
|
|
|
if (playWhenReady) { |
|
|
|
controlsBinding.playPause.setIconResource(R.drawable.ic_pause_24); |
|
|
|
return; |
|
|
|
} |
|
|
|
controlsBinding.playPause.setIconResource(R.drawable.ic_play_states); |
|
|
|
} |
|
|
|
// private void updatePlayPauseDrawable(final boolean playWhenReady) { |
|
|
|
// if (playWhenReady) { |
|
|
|
// controlsBinding.playPause.setIconResource(R.drawable.ic_pause_24); |
|
|
|
// return; |
|
|
|
// } |
|
|
|
// controlsBinding.playPause.setIconResource(R.drawable.ic_play_states); |
|
|
|
// } |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) { |
|
|
@ -343,15 +343,14 @@ public class VideoPlayerViewHelper implements Player.EventListener { |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onPlayerError(final ExoPlaybackException error) { |
|
|
|
public void onPlayerError(@NonNull final ExoPlaybackException error) { |
|
|
|
Log.e(TAG, "onPlayerError", error); |
|
|
|
} |
|
|
|
|
|
|
|
public float toggleMute() { |
|
|
|
if (player == null) return 0; |
|
|
|
private void toggleMute() { |
|
|
|
if (player == null) return; |
|
|
|
final float vol = player.getVolume() == 0f ? 1f : 0f; |
|
|
|
player.setVolume(vol); |
|
|
|
return vol; |
|
|
|
} |
|
|
|
|
|
|
|
// public void togglePlayback() { |
|
|
@ -370,85 +369,85 @@ public class VideoPlayerViewHelper implements Player.EventListener { |
|
|
|
player.release(); |
|
|
|
player = null; |
|
|
|
} |
|
|
|
if (positionUpdateHandler != null) { |
|
|
|
if (positionChecker != null) { |
|
|
|
positionUpdateHandler.removeCallbacks(positionChecker); |
|
|
|
positionChecker = null; |
|
|
|
} |
|
|
|
positionUpdateHandler = null; |
|
|
|
} |
|
|
|
// if (positionUpdateHandler != null) { |
|
|
|
// if (positionChecker != null) { |
|
|
|
// positionUpdateHandler.removeCallbacks(positionChecker); |
|
|
|
// positionChecker = null; |
|
|
|
// } |
|
|
|
// positionUpdateHandler = null; |
|
|
|
// } |
|
|
|
} |
|
|
|
|
|
|
|
public void pause() { |
|
|
|
if (player != null) { |
|
|
|
player.pause(); |
|
|
|
} |
|
|
|
if (positionUpdateHandler != null) { |
|
|
|
if (positionChecker != null) { |
|
|
|
positionUpdateHandler.removeCallbacks(positionChecker); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void resetTimeline() { |
|
|
|
if (player == null) { |
|
|
|
enableControls(false); |
|
|
|
return; |
|
|
|
} |
|
|
|
setupTimeline(); |
|
|
|
final long currentPosition = player.getCurrentPosition(); |
|
|
|
controlsBinding.timeline.setValue(Math.min(currentPosition, player.getDuration())); |
|
|
|
setupControls(); |
|
|
|
// if (positionUpdateHandler != null) { |
|
|
|
// if (positionChecker != null) { |
|
|
|
// positionUpdateHandler.removeCallbacks(positionChecker); |
|
|
|
// } |
|
|
|
// } |
|
|
|
} |
|
|
|
|
|
|
|
public void removeCallbacks() { |
|
|
|
if (player != null) { |
|
|
|
player.removeListener(listener); |
|
|
|
player.removeAudioListener(audioListener); |
|
|
|
} |
|
|
|
controlsBinding.timeline.removeOnChangeListener(onChangeListener); |
|
|
|
controlsBinding.timeline.setLabelFormatter(null); |
|
|
|
controlsBinding.playPause.setOnClickListener(null); |
|
|
|
controlsBinding.mute.setOnClickListener(null); |
|
|
|
controlsBinding.rewWithAmount.setOnClickListener(null); |
|
|
|
controlsBinding.ffWithAmount.setOnClickListener(null); |
|
|
|
controlsBinding.speed.setOnClickListener(null); |
|
|
|
} |
|
|
|
// public void resetTimeline() { |
|
|
|
// if (player == null) { |
|
|
|
// enableControls(false); |
|
|
|
// return; |
|
|
|
// } |
|
|
|
// setupTimeline(); |
|
|
|
// final long currentPosition = player.getCurrentPosition(); |
|
|
|
// controlsBinding.timeline.setValue(Math.min(currentPosition, player.getDuration())); |
|
|
|
// setupControls(); |
|
|
|
// } |
|
|
|
|
|
|
|
private static class PositionCheckRunnable implements Runnable { |
|
|
|
private final Handler positionUpdateHandler; |
|
|
|
private final SimpleExoPlayer player; |
|
|
|
private final Slider timeline; |
|
|
|
private final AppCompatTextView fromTime; |
|
|
|
|
|
|
|
public PositionCheckRunnable(final Handler positionUpdateHandler, |
|
|
|
final SimpleExoPlayer simpleExoPlayer, |
|
|
|
final Slider slider, |
|
|
|
final AppCompatTextView fromTime) { |
|
|
|
this.positionUpdateHandler = positionUpdateHandler; |
|
|
|
this.player = simpleExoPlayer; |
|
|
|
this.timeline = slider; |
|
|
|
this.fromTime = fromTime; |
|
|
|
} |
|
|
|
// public void removeCallbacks() { |
|
|
|
// if (player != null) { |
|
|
|
// player.removeListener(listener); |
|
|
|
// player.removeAudioListener(audioListener); |
|
|
|
// } |
|
|
|
// controlsBinding.timeline.removeOnChangeListener(onChangeListener); |
|
|
|
// controlsBinding.timeline.setLabelFormatter(null); |
|
|
|
// controlsBinding.playPause.setOnClickListener(null); |
|
|
|
// controlsBinding.mute.setOnClickListener(null); |
|
|
|
// controlsBinding.rewWithAmount.setOnClickListener(null); |
|
|
|
// controlsBinding.ffWithAmount.setOnClickListener(null); |
|
|
|
// controlsBinding.speed.setOnClickListener(null); |
|
|
|
// } |
|
|
|
|
|
|
|
@Override |
|
|
|
public void run() { |
|
|
|
if (positionUpdateHandler == null) return; |
|
|
|
positionUpdateHandler.removeCallbacks(this); |
|
|
|
if (player == null) return; |
|
|
|
final long currentPosition = player.getCurrentPosition(); |
|
|
|
final long duration = player.getDuration(); |
|
|
|
if (duration == TIME_UNSET) { |
|
|
|
timeline.setValueFrom(0); |
|
|
|
timeline.setValueTo(0); |
|
|
|
timeline.setEnabled(false); |
|
|
|
return; |
|
|
|
} |
|
|
|
timeline.setValue(Math.min(currentPosition, duration)); |
|
|
|
fromTime.setText(TextUtils.millisToTimeString(currentPosition)); |
|
|
|
positionUpdateHandler.postDelayed(this, RECURRING_DELAY); |
|
|
|
} |
|
|
|
} |
|
|
|
// private static class PositionCheckRunnable implements Runnable { |
|
|
|
// private final Handler positionUpdateHandler; |
|
|
|
// private final SimpleExoPlayer player; |
|
|
|
// private final Slider timeline; |
|
|
|
// private final AppCompatTextView fromTime; |
|
|
|
// |
|
|
|
// public PositionCheckRunnable(final Handler positionUpdateHandler, |
|
|
|
// final SimpleExoPlayer simpleExoPlayer, |
|
|
|
// final Slider slider, |
|
|
|
// final AppCompatTextView fromTime) { |
|
|
|
// this.positionUpdateHandler = positionUpdateHandler; |
|
|
|
// this.player = simpleExoPlayer; |
|
|
|
// this.timeline = slider; |
|
|
|
// this.fromTime = fromTime; |
|
|
|
// } |
|
|
|
// |
|
|
|
// @Override |
|
|
|
// public void run() { |
|
|
|
// if (positionUpdateHandler == null) return; |
|
|
|
// positionUpdateHandler.removeCallbacks(this); |
|
|
|
// if (player == null) return; |
|
|
|
// final long currentPosition = player.getCurrentPosition(); |
|
|
|
// final long duration = player.getDuration(); |
|
|
|
// if (duration == TIME_UNSET) { |
|
|
|
// timeline.setValueFrom(0); |
|
|
|
// timeline.setValueTo(0); |
|
|
|
// timeline.setEnabled(false); |
|
|
|
// return; |
|
|
|
// } |
|
|
|
// timeline.setValue(Math.min(currentPosition, duration)); |
|
|
|
// fromTime.setText(TextUtils.millisToTimeString(currentPosition)); |
|
|
|
// positionUpdateHandler.postDelayed(this, RECURRING_DELAY); |
|
|
|
// } |
|
|
|
// } |
|
|
|
|
|
|
|
public interface VideoPlayerCallback { |
|
|
|
void onThumbnailLoaded(); |
|
|
|