From 362e66cf0857cf7432303c5e47e806d808224d3d Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 14 May 2021 20:56:18 +0200 Subject: [PATCH 1/5] Removed code from MediaPlayerActivity that only affects the audio player --- .../activity/MediaplayerActivity.java | 29 ++----------------- .../activity/VideoplayerActivity.java | 10 ------- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java index 4b5822ac7..fbcab03a4 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -65,7 +65,6 @@ import io.reactivex.schedulers.Schedulers; */ public abstract class MediaplayerActivity extends CastEnabledActivity implements OnSeekBarChangeListener { private static final String TAG = "MediaplayerActivity"; - private static final String PREFS = "MediaPlayerActivityPreferences"; PlaybackController controller; @@ -144,11 +143,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements finish(); } - @Override - public void onPlaybackSpeedChange() { - MediaplayerActivity.this.onPlaybackSpeedChange(); - } - @Override protected void setScreenOn(boolean enable) { super.setScreenOn(enable); @@ -169,20 +163,12 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements } } - private void onPlaybackSpeedChange() { - updatePlaybackSpeedButtonText(); - } - - void chooseTheme() { - setTheme(UserPreferences.getTheme()); - } - void setScreenOn(boolean enable) { } @Override protected void onCreate(Bundle savedInstanceState) { - chooseTheme(); + setTheme(R.style.Theme_AntennaPod_VideoPlayer); super.onCreate(savedInstanceState); Log.d(TAG, "onCreate()"); @@ -454,19 +440,10 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements showTimeLeft = UserPreferences.shouldShowRemainingTime(); onPositionObserverUpdate(); checkFavorite(); - updatePlaybackSpeedButton(); - } - - void updatePlaybackSpeedButton() { - // Only meaningful on AudioplayerActivity, where it is overridden. - } - - void updatePlaybackSpeedButtonText() { - // Only meaningful on AudioplayerActivity, where it is overridden. } void setupGUI() { - setContentView(getContentViewResourceId()); + setContentView(R.layout.videoplayer_activity); sbPosition = findViewById(R.id.sbPosition); txtvPosition = findViewById(R.id.txtvPosition); cardViewSeek = findViewById(R.id.cardViewSeek); @@ -571,8 +548,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements controller.seekTo(curr + UserPreferences.getFastForwardSecs() * 1000); } - protected abstract int getContentViewResourceId(); - private void handleError(int errorCode) { final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this); errorDialog.setTitle(R.string.error_label); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index f7b122c3d..b3bf0ebc8 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -69,11 +69,6 @@ public class VideoplayerActivity extends MediaplayerActivity { private FrameLayout videoframe; private ImageView skipAnimationView; - @Override - protected void chooseTheme() { - setTheme(R.style.Theme_AntennaPod_VideoPlayer); - } - @SuppressLint("AppCompatMethod") @Override protected void onCreate(Bundle savedInstanceState) { @@ -400,11 +395,6 @@ public class VideoplayerActivity extends MediaplayerActivity { hideVideoControls(true); } - @Override - protected int getContentViewResourceId() { - return R.layout.videoplayer_activity; - } - @Override protected void setScreenOn(boolean enable) { super.setScreenOn(enable); From c3d7209f09f3b6c3974ada7836fe08f9d131e09b Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 14 May 2021 21:39:27 +0200 Subject: [PATCH 2/5] Moved all code from MediaPlayerActivity to VideoPlayerActivity --- .../activity/MediaplayerActivity.java | 633 ------------------ .../activity/VideoplayerActivity.java | 547 ++++++++++++++- 2 files changed, 513 insertions(+), 667 deletions(-) delete mode 100644 app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java deleted file mode 100644 index fbcab03a4..000000000 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ /dev/null @@ -1,633 +0,0 @@ -package de.danoeh.antennapod.activity; - -import android.annotation.TargetApi; -import android.content.Intent; -import android.graphics.PixelFormat; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.ImageButton; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; - -import com.bumptech.glide.Glide; - -import de.danoeh.antennapod.core.event.ServiceEvent; -import de.danoeh.antennapod.view.PlayButton; -import org.apache.commons.lang3.StringUtils; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; - -import java.text.NumberFormat; - -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.cardview.widget.CardView; -import androidx.core.app.ActivityOptionsCompat; -import androidx.interpolator.view.animation.FastOutSlowInInterpolator; - -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.event.PlaybackPositionEvent; -import de.danoeh.antennapod.model.feed.FeedItem; -import de.danoeh.antennapod.model.feed.FeedMedia; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.service.playback.PlaybackService; -import de.danoeh.antennapod.core.storage.DBReader; -import de.danoeh.antennapod.core.storage.DBWriter; -import de.danoeh.antennapod.core.util.Converter; -import de.danoeh.antennapod.core.util.FeedItemUtil; -import de.danoeh.antennapod.core.util.IntentUtils; -import de.danoeh.antennapod.core.util.ShareUtils; -import de.danoeh.antennapod.core.util.StorageUtils; -import de.danoeh.antennapod.core.util.TimeSpeedConverter; -import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil; -import de.danoeh.antennapod.core.util.playback.MediaPlayerError; -import de.danoeh.antennapod.model.playback.Playable; -import de.danoeh.antennapod.core.util.playback.PlaybackController; -import de.danoeh.antennapod.dialog.PlaybackControlsDialog; -import de.danoeh.antennapod.dialog.ShareDialog; -import de.danoeh.antennapod.dialog.SkipPreferenceDialog; -import de.danoeh.antennapod.dialog.SleepTimerDialog; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; - -/** - * Provides general features which are both needed for playing audio and video - * files. - */ -public abstract class MediaplayerActivity extends CastEnabledActivity implements OnSeekBarChangeListener { - private static final String TAG = "MediaplayerActivity"; - - PlaybackController controller; - - private TextView txtvPosition; - private TextView txtvLength; - SeekBar sbPosition; - private ImageButton butRev; - private TextView txtvRev; - private PlayButton butPlay; - private ImageButton butFF; - private TextView txtvFF; - private ImageButton butSkip; - private CardView cardViewSeek; - private TextView txtvSeek; - - private boolean showTimeLeft = false; - - private boolean isFavorite = false; - - private Disposable disposable; - - private PlaybackController newPlaybackController() { - return new PlaybackController(this) { - @Override - public void onPositionObserverUpdate() { - MediaplayerActivity.this.onPositionObserverUpdate(); - } - - @Override - public void onBufferStart() { - MediaplayerActivity.this.onBufferStart(); - } - - @Override - public void onBufferEnd() { - MediaplayerActivity.this.onBufferEnd(); - } - - @Override - public void onBufferUpdate(float progress) { - MediaplayerActivity.this.onBufferUpdate(progress); - } - - @Override - public void handleError(int code) { - MediaplayerActivity.this.handleError(code); - } - - @Override - public void onReloadNotification(int code) { - MediaplayerActivity.this.onReloadNotification(code); - } - - @Override - public void onSleepTimerUpdate() { - supportInvalidateOptionsMenu(); - } - - @Override - protected void updatePlayButtonShowsPlay(boolean showPlay) { - butPlay.setIsShowPlay(showPlay); - } - - @Override - public void loadMediaInfo() { - MediaplayerActivity.this.loadMediaInfo(); - } - - @Override - public void onAwaitingVideoSurface() { - MediaplayerActivity.this.onAwaitingVideoSurface(); - } - - @Override - public void onPlaybackEnd() { - finish(); - } - - @Override - protected void setScreenOn(boolean enable) { - super.setScreenOn(enable); - MediaplayerActivity.this.setScreenOn(enable); - } - }; - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(PlaybackPositionEvent event) { - onPositionObserverUpdate(); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onPlaybackServiceChanged(ServiceEvent event) { - if (event.action == ServiceEvent.Action.SERVICE_SHUT_DOWN) { - finish(); - } - } - - void setScreenOn(boolean enable) { - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - setTheme(R.style.Theme_AntennaPod_VideoPlayer); - super.onCreate(savedInstanceState); - - Log.d(TAG, "onCreate()"); - StorageUtils.checkStorageAvailability(this); - - getWindow().setFormat(PixelFormat.TRANSPARENT); - setupGUI(); - } - - @Override - protected void onPause() { - if (!PictureInPictureUtil.isInPictureInPictureMode(this)) { - if (controller != null) { - controller.reinitServiceIfPaused(); - controller.pause(); - } - } - super.onPause(); - } - - /** - * Should be used to switch to another player activity if the mime type is - * not the correct one for the current activity. - */ - protected abstract void onReloadNotification(int notificationCode); - - /** - * Should be used to inform the user that the PlaybackService is currently - * buffering. - */ - protected void onBufferStart() { - - } - - /** - * Should be used to hide the view that was showing the 'buffering'-message. - */ - protected void onBufferEnd() { - - } - - private void onBufferUpdate(float progress) { - if (sbPosition != null) { - sbPosition.setSecondaryProgress((int) (progress * sbPosition.getMax())); - } - } - - @Override - protected void onStart() { - super.onStart(); - controller = newPlaybackController(); - controller.init(); - loadMediaInfo(); - onPositionObserverUpdate(); - EventBus.getDefault().register(this); - } - - @Override - protected void onStop() { - Log.d(TAG, "onStop()"); - if (controller != null) { - controller.release(); - controller = null; // prevent leak - } - if (disposable != null) { - disposable.dispose(); - } - EventBus.getDefault().unregister(this); - super.onStop(); - } - - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - @Override - public void onTrimMemory(int level) { - super.onTrimMemory(level); - Glide.get(this).trimMemory(level); - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - Glide.get(this).clearMemory(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - requestCastButton(menu); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.mediaplayer, menu); - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - if (controller == null) { - return false; - } - Playable media = controller.getMedia(); - boolean isFeedMedia = (media instanceof FeedMedia); - - menu.findItem(R.id.open_feed_item).setVisible(isFeedMedia); // FeedMedia implies it belongs to a Feed - - boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null ); - menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink); - - boolean isItemAndHasLink = isFeedMedia && - ShareUtils.hasLinkToShare(((FeedMedia) media).getItem()); - - boolean isItemHasDownloadLink = isFeedMedia && ((FeedMedia) media).getDownload_url() != null; - - menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink); - - menu.findItem(R.id.add_to_favorites_item).setVisible(false); - menu.findItem(R.id.remove_from_favorites_item).setVisible(false); - if (isFeedMedia) { - menu.findItem(R.id.add_to_favorites_item).setVisible(!isFavorite); - menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite); - } - - menu.findItem(R.id.set_sleeptimer_item).setVisible(!controller.sleepTimerActive()); - menu.findItem(R.id.disable_sleeptimer_item).setVisible(controller.sleepTimerActive()); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (controller == null) { - return false; - } - Playable media = controller.getMedia(); - if (item.getItemId() == android.R.id.home) { - Intent intent = new Intent(MediaplayerActivity.this, - MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP - | Intent.FLAG_ACTIVITY_NEW_TASK); - - View cover = findViewById(R.id.imgvCover); - if (cover != null) { - ActivityOptionsCompat options = ActivityOptionsCompat - .makeSceneTransitionAnimation(MediaplayerActivity.this, cover, "coverTransition"); - startActivity(intent, options.toBundle()); - } else { - startActivity(intent); - } - finish(); - return true; - } else { - if (media != null) { - final @Nullable FeedItem feedItem = getFeedItem(media); // some options option requires FeedItem - switch (item.getItemId()) { - case R.id.add_to_favorites_item: - if (feedItem != null) { - DBWriter.addFavoriteItem(feedItem); - isFavorite = true; - invalidateOptionsMenu(); - } - break; - case R.id.remove_from_favorites_item: - if (feedItem != null) { - DBWriter.removeFavoriteItem(feedItem); - isFavorite = false; - invalidateOptionsMenu(); - } - break; - case R.id.disable_sleeptimer_item: // Fall-through - case R.id.set_sleeptimer_item: - new SleepTimerDialog().show(getSupportFragmentManager(), "SleepTimerDialog"); - break; - case R.id.audio_controls: - PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(); - dialog.show(getSupportFragmentManager(), "playback_controls"); - break; - case R.id.open_feed_item: - if (feedItem != null) { - Intent intent = MainActivity.getIntentToOpenFeed(this, feedItem.getFeedId()); - startActivity(intent); - } - break; - case R.id.visit_website_item: - IntentUtils.openInBrowser(MediaplayerActivity.this, getWebsiteLinkWithFallback(media)); - break; - case R.id.share_item: - if (feedItem != null) { - ShareDialog shareDialog = ShareDialog.newInstance(feedItem); - shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog"); - } - break; - default: - return false; - } - return true; - } else { - return false; - } - } - } - - private static String getWebsiteLinkWithFallback(Playable media) { - if (media == null) { - return null; - } else if (StringUtils.isNotBlank(media.getWebsiteLink())) { - return media.getWebsiteLink(); - } else if (media instanceof FeedMedia) { - return FeedItemUtil.getLinkWithFallback(((FeedMedia)media).getItem()); - } - return null; - } - - @Override - protected void onResume() { - super.onResume(); - Log.d(TAG, "onResume()"); - StorageUtils.checkStorageAvailability(this); - } - - /** - * Called by 'handleStatus()' when the PlaybackService is waiting for - * a video surface. - */ - protected abstract void onAwaitingVideoSurface(); - - void onPositionObserverUpdate() { - if (controller == null || txtvPosition == null || txtvLength == null) { - return; - } - - TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); - int currentPosition = converter.convert(controller.getPosition()); - int duration = converter.convert(controller.getDuration()); - int remainingTime = converter.convert( - controller.getDuration() - controller.getPosition()); - Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition)); - if (currentPosition == PlaybackService.INVALID_TIME || - duration == PlaybackService.INVALID_TIME) { - Log.w(TAG, "Could not react to position observer update because of invalid time"); - return; - } - txtvPosition.setText(Converter.getDurationStringLong(currentPosition)); - if (showTimeLeft) { - txtvLength.setText("-" + Converter.getDurationStringLong(remainingTime)); - } else { - txtvLength.setText(Converter.getDurationStringLong(duration)); - } - updateProgressbarPosition(currentPosition, duration); - } - - private void updateProgressbarPosition(int position, int duration) { - Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")"); - if(sbPosition == null) { - return; - } - float progress = ((float) position) / duration; - sbPosition.setProgress((int) (progress * sbPosition.getMax())); - } - - /** - * Load information about the media that is going to be played or currently - * being played. This method will be called when the activity is connected - * to the PlaybackService to ensure that the activity has the right - * FeedMedia object. - */ - void loadMediaInfo() { - Log.d(TAG, "loadMediaInfo()"); - if (controller == null || controller.getMedia() == null) { - return; - } - showTimeLeft = UserPreferences.shouldShowRemainingTime(); - onPositionObserverUpdate(); - checkFavorite(); - } - - void setupGUI() { - setContentView(R.layout.videoplayer_activity); - sbPosition = findViewById(R.id.sbPosition); - txtvPosition = findViewById(R.id.txtvPosition); - cardViewSeek = findViewById(R.id.cardViewSeek); - txtvSeek = findViewById(R.id.txtvSeek); - - showTimeLeft = UserPreferences.shouldShowRemainingTime(); - Log.d("timeleft", showTimeLeft ? "true" : "false"); - txtvLength = findViewById(R.id.txtvLength); - if (txtvLength != null) { - txtvLength.setOnClickListener(v -> { - showTimeLeft = !showTimeLeft; - Playable media = controller.getMedia(); - if (media == null) { - return; - } - - TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); - String length; - if (showTimeLeft) { - int remainingTime = converter.convert( - media.getDuration() - media.getPosition()); - - length = "-" + Converter.getDurationStringLong(remainingTime); - } else { - int duration = converter.convert(media.getDuration()); - length = Converter.getDurationStringLong(duration); - } - txtvLength.setText(length); - - UserPreferences.setShowRemainTimeSetting(showTimeLeft); - Log.d("timeleft on click", showTimeLeft ? "true" : "false"); - }); - } - - butRev = findViewById(R.id.butRev); - txtvRev = findViewById(R.id.txtvRev); - if (txtvRev != null) { - txtvRev.setText(NumberFormat.getInstance().format(UserPreferences.getRewindSecs())); - } - butPlay = findViewById(R.id.butPlay); - butPlay.setIsVideoScreen(true); - butFF = findViewById(R.id.butFF); - txtvFF = findViewById(R.id.txtvFF); - if (txtvFF != null) { - txtvFF.setText(NumberFormat.getInstance().format(UserPreferences.getFastForwardSecs())); - } - butSkip = findViewById(R.id.butSkip); - - // SEEKBAR SETUP - - sbPosition.setOnSeekBarChangeListener(this); - - // BUTTON SETUP - - if (butRev != null) { - butRev.setOnClickListener(v -> onRewind()); - butRev.setOnLongClickListener(v -> { - SkipPreferenceDialog.showSkipPreference(MediaplayerActivity.this, - SkipPreferenceDialog.SkipDirection.SKIP_REWIND, txtvRev); - return true; - }); - } - - butPlay.setOnClickListener(v -> onPlayPause()); - - if (butFF != null) { - butFF.setOnClickListener(v -> onFastForward()); - butFF.setOnLongClickListener(v -> { - SkipPreferenceDialog.showSkipPreference(MediaplayerActivity.this, - SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, txtvFF); - return false; - }); - } - - if (butSkip != null) { - butSkip.setOnClickListener(v -> - IntentUtils.sendLocalBroadcast(MediaplayerActivity.this, PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); - } - } - - void onRewind() { - if (controller == null) { - return; - } - int curr = controller.getPosition(); - controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000); - } - - void onPlayPause() { - if(controller == null) { - return; - } - controller.init(); - controller.playPause(); - } - - void onFastForward() { - if (controller == null) { - return; - } - int curr = controller.getPosition(); - controller.seekTo(curr + UserPreferences.getFastForwardSecs() * 1000); - } - - private void handleError(int errorCode) { - final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this); - errorDialog.setTitle(R.string.error_label); - errorDialog.setMessage(MediaPlayerError.getErrorString(this, errorCode)); - errorDialog.setNeutralButton("OK", - (dialog, which) -> { - dialog.dismiss(); - finish(); - } - ); - errorDialog.create().show(); - } - - private float prog; - - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (controller == null || txtvLength == null) { - return; - } - if (fromUser) { - prog = progress / ((float) seekBar.getMax()); - TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); - int position = converter.convert((int) (prog * controller.getDuration())); - txtvSeek.setText(Converter.getDurationStringLong(position)); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - cardViewSeek.setScaleX(.8f); - cardViewSeek.setScaleY(.8f); - cardViewSeek.animate() - .setInterpolator(new FastOutSlowInInterpolator()) - .alpha(1f).scaleX(1f).scaleY(1f) - .setDuration(200) - .start(); - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - if (controller != null) { - controller.seekTo((int) (prog * controller.getDuration())); - } - cardViewSeek.setScaleX(1f); - cardViewSeek.setScaleY(1f); - cardViewSeek.animate() - .setInterpolator(new FastOutSlowInInterpolator()) - .alpha(0f).scaleX(.8f).scaleY(.8f) - .setDuration(200) - .start(); - } - - private void checkFavorite() { - FeedItem feedItem = getFeedItem(controller.getMedia()); - if (feedItem == null) { - return; - } - if (disposable != null) { - disposable.dispose(); - } - disposable = Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - item -> { - boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE); - if (isFavorite != isFav) { - isFavorite = isFav; - invalidateOptionsMenu(); - } - }, error -> Log.e(TAG, Log.getStackTraceString(error))); - } - - @Nullable - private static FeedItem getFeedItem(@Nullable Playable playable) { - if (playable instanceof FeedMedia) { - return ((FeedMedia) playable).getItem(); - } else { - return null; - } - } -} diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index b3bf0ebc8..dc4345c21 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -1,7 +1,9 @@ package de.danoeh.antennapod.activity; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.content.Intent; +import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; import android.media.AudioManager; import android.os.Build; @@ -9,12 +11,19 @@ import android.os.Bundle; import android.os.Handler; import android.view.Gravity; import android.view.KeyEvent; +import android.view.MenuInflater; import android.view.animation.AlphaAnimation; import android.view.animation.AnimationSet; import android.view.animation.ScaleAnimation; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.cardview.widget.CardView; +import androidx.core.app.ActivityOptionsCompat; import androidx.core.view.WindowCompat; import androidx.appcompat.app.ActionBar; import android.util.Log; @@ -33,21 +42,51 @@ import android.widget.ProgressBar; import android.widget.SeekBar; import java.lang.ref.WeakReference; +import java.text.NumberFormat; import java.util.concurrent.atomic.AtomicBoolean; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; +import com.bumptech.glide.Glide; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; +import de.danoeh.antennapod.core.event.ServiceEvent; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.service.playback.PlayerStatus; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.FeedItemUtil; +import de.danoeh.antennapod.core.util.IntentUtils; +import de.danoeh.antennapod.core.util.ShareUtils; +import de.danoeh.antennapod.core.util.StorageUtils; +import de.danoeh.antennapod.core.util.TimeSpeedConverter; import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil; +import de.danoeh.antennapod.core.util.playback.MediaPlayerError; +import de.danoeh.antennapod.core.util.playback.PlaybackController; +import de.danoeh.antennapod.dialog.PlaybackControlsDialog; +import de.danoeh.antennapod.dialog.ShareDialog; +import de.danoeh.antennapod.dialog.SkipPreferenceDialog; +import de.danoeh.antennapod.dialog.SleepTimerDialog; +import de.danoeh.antennapod.model.feed.FeedItem; +import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.model.playback.Playable; import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter; import de.danoeh.antennapod.view.AspectRatioVideoView; +import de.danoeh.antennapod.view.PlayButton; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import org.apache.commons.lang3.StringUtils; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** * Activity for playing video files. */ -public class VideoplayerActivity extends MediaplayerActivity { +public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.OnSeekBarChangeListener { private static final String TAG = "VideoplayerActivity"; /** @@ -68,6 +107,23 @@ public class VideoplayerActivity extends MediaplayerActivity { private ProgressBar progressIndicator; private FrameLayout videoframe; private ImageView skipAnimationView; + private TextView txtvPosition; + private TextView txtvLength; + private SeekBar sbPosition; + private ImageButton butRev; + private TextView txtvRev; + private PlayButton butPlay; + private ImageButton butFF; + private TextView txtvFF; + private ImageButton butSkip; + private CardView cardViewSeek; + private TextView txtvSeek; + + private PlaybackController controller; + private boolean showTimeLeft = false; + private boolean isFavorite = false; + private Disposable disposable; + private float prog; @SuppressLint("AppCompatMethod") @Override @@ -75,13 +131,21 @@ public class VideoplayerActivity extends MediaplayerActivity { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY); // has to be called before setting layout content + setTheme(R.style.Theme_AntennaPod_VideoPlayer); super.onCreate(savedInstanceState); + + Log.d(TAG, "onCreate()"); + StorageUtils.checkStorageAvailability(this); + + getWindow().setFormat(PixelFormat.TRANSPARENT); + setupGUI(); getSupportActionBar().setBackgroundDrawable(new ColorDrawable(0x80000000)); } @Override protected void onResume() { super.onResume(); + StorageUtils.checkStorageAvailability(this); if (PlaybackService.isCasting()) { Intent intent = PlaybackService.getPlayerActivityIntent(this); if (!intent.getComponent().getClassName().equals(VideoplayerActivity.class.getName())) { @@ -94,6 +158,14 @@ public class VideoplayerActivity extends MediaplayerActivity { @Override protected void onStop() { + if (controller != null) { + controller.release(); + controller = null; // prevent leak + } + if (disposable != null) { + disposable.dispose(); + } + EventBus.getDefault().unregister(this); super.onStop(); if (!PictureInPictureUtil.isInPictureInPictureMode(this)) { videoControlsHider.stop(); @@ -109,6 +181,16 @@ public class VideoplayerActivity extends MediaplayerActivity { } } + @Override + protected void onStart() { + super.onStart(); + controller = newPlaybackController(); + controller.init(); + loadMediaInfo(); + onPositionObserverUpdate(); + EventBus.getDefault().register(this); + } + @Override protected void onPause() { if (!PictureInPictureUtil.isInPictureInPictureMode(this)) { @@ -126,9 +208,94 @@ public class VideoplayerActivity extends MediaplayerActivity { super.onDestroy(); } + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + Glide.get(this).trimMemory(level); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + Glide.get(this).clearMemory(); + } + + private PlaybackController newPlaybackController() { + return new PlaybackController(this) { + @Override + public void onPositionObserverUpdate() { + VideoplayerActivity.this.onPositionObserverUpdate(); + } + + @Override + public void onBufferStart() { + VideoplayerActivity.this.onBufferStart(); + } + + @Override + public void onBufferEnd() { + VideoplayerActivity.this.onBufferEnd(); + } + + @Override + public void onBufferUpdate(float progress) { + if (sbPosition != null) { + sbPosition.setSecondaryProgress((int) (progress * sbPosition.getMax())); + } + } + + @Override + public void handleError(int code) { + VideoplayerActivity.this.handleError(code); + } + + @Override + public void onReloadNotification(int code) { + VideoplayerActivity.this.onReloadNotification(code); + } + + @Override + public void onSleepTimerUpdate() { + supportInvalidateOptionsMenu(); + } + + @Override + protected void updatePlayButtonShowsPlay(boolean showPlay) { + butPlay.setIsShowPlay(showPlay); + } + + @Override + public void loadMediaInfo() { + VideoplayerActivity.this.loadMediaInfo(); + } + + @Override + public void onAwaitingVideoSurface() { + VideoplayerActivity.this.onAwaitingVideoSurface(); + } + + @Override + public void onPlaybackEnd() { + finish(); + } + + @Override + protected void setScreenOn(boolean enable) { + super.setScreenOn(enable); + VideoplayerActivity.this.setScreenOn(enable); + } + }; + } + protected void loadMediaInfo() { - super.loadMediaInfo(); + Log.d(TAG, "loadMediaInfo()"); + if (controller == null || controller.getMedia() == null) { + return; + } + showTimeLeft = UserPreferences.shouldShowRemainingTime(); + onPositionObserverUpdate(); + checkFavorite(); Playable media = controller.getMedia(); if (media != null) { getSupportActionBar().setSubtitle(media.getEpisodeTitle()); @@ -136,12 +303,90 @@ public class VideoplayerActivity extends MediaplayerActivity { } } - @Override protected void setupGUI() { if (isSetup.getAndSet(true)) { return; } - super.setupGUI(); + setContentView(R.layout.videoplayer_activity); + sbPosition = findViewById(R.id.sbPosition); + txtvPosition = findViewById(R.id.txtvPosition); + cardViewSeek = findViewById(R.id.cardViewSeek); + txtvSeek = findViewById(R.id.txtvSeek); + + showTimeLeft = UserPreferences.shouldShowRemainingTime(); + Log.d("timeleft", showTimeLeft ? "true" : "false"); + txtvLength = findViewById(R.id.txtvLength); + if (txtvLength != null) { + txtvLength.setOnClickListener(v -> { + showTimeLeft = !showTimeLeft; + Playable media = controller.getMedia(); + if (media == null) { + return; + } + + TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); + String length; + if (showTimeLeft) { + int remainingTime = converter.convert( + media.getDuration() - media.getPosition()); + + length = "-" + Converter.getDurationStringLong(remainingTime); + } else { + int duration = converter.convert(media.getDuration()); + length = Converter.getDurationStringLong(duration); + } + txtvLength.setText(length); + + UserPreferences.setShowRemainTimeSetting(showTimeLeft); + Log.d("timeleft on click", showTimeLeft ? "true" : "false"); + }); + } + + butRev = findViewById(R.id.butRev); + txtvRev = findViewById(R.id.txtvRev); + if (txtvRev != null) { + txtvRev.setText(NumberFormat.getInstance().format(UserPreferences.getRewindSecs())); + } + butPlay = findViewById(R.id.butPlay); + butPlay.setIsVideoScreen(true); + butFF = findViewById(R.id.butFF); + txtvFF = findViewById(R.id.txtvFF); + if (txtvFF != null) { + txtvFF.setText(NumberFormat.getInstance().format(UserPreferences.getFastForwardSecs())); + } + butSkip = findViewById(R.id.butSkip); + + // SEEKBAR SETUP + + sbPosition.setOnSeekBarChangeListener(this); + + // BUTTON SETUP + + if (butRev != null) { + butRev.setOnClickListener(v -> onRewind()); + butRev.setOnLongClickListener(v -> { + SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this, + SkipPreferenceDialog.SkipDirection.SKIP_REWIND, txtvRev); + return true; + }); + } + + butPlay.setOnClickListener(v -> onPlayPause()); + + if (butFF != null) { + butFF.setOnClickListener(v -> onFastForward()); + butFF.setOnLongClickListener(v -> { + SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this, + SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, txtvFF); + return false; + }); + } + + if (butSkip != null) { + butSkip.setOnClickListener(v -> + IntentUtils.sendLocalBroadcast(VideoplayerActivity.this, PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); + } + getSupportActionBar().setDisplayHomeAsUpEnabled(true); controls = findViewById(R.id.controls); videoOverlay = findViewById(R.id.overlay); @@ -163,7 +408,6 @@ public class VideoplayerActivity extends MediaplayerActivity { videoview.setAvailableSize(videoframe.getWidth(), videoframe.getHeight())); } - @Override protected void onAwaitingVideoSurface() { setupVideoAspectRatio(); if (videoSurfaceCreated && controller != null) { @@ -273,24 +517,45 @@ public class VideoplayerActivity extends MediaplayerActivity { videoControlsShowing = !videoControlsShowing; } - @Override - protected void onRewind() { - super.onRewind(); + void onRewind() { + if (controller == null) { + return; + } + int curr = controller.getPosition(); + controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000); setupVideoControlsToggler(); } - @Override - protected void onPlayPause() { - super.onPlayPause(); + void onPlayPause() { + if(controller == null) { + return; + } + controller.init(); + controller.playPause(); setupVideoControlsToggler(); } - @Override - protected void onFastForward() { - super.onFastForward(); + void onFastForward() { + if (controller == null) { + return; + } + int curr = controller.getPosition(); + controller.seekTo(curr + UserPreferences.getFastForwardSecs() * 1000); setupVideoControlsToggler(); } + private void handleError(int errorCode) { + final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this); + errorDialog.setTitle(R.string.error_label); + errorDialog.setMessage(MediaPlayerError.getErrorString(this, errorCode)); + errorDialog.setNeutralButton("OK", + (dialog, which) -> { + dialog.dismiss(); + finish(); + } + ); + errorDialog.create().show(); + } private final SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() { @Override @@ -321,8 +586,6 @@ public class VideoplayerActivity extends MediaplayerActivity { } }; - - @Override protected void onReloadNotification(int notificationCode) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && PictureInPictureUtil.isInPictureInPictureMode(this)) { if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO @@ -339,24 +602,10 @@ public class VideoplayerActivity extends MediaplayerActivity { } } - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - super.onStartTrackingTouch(seekBar); - videoControlsHider.stop(); - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - super.onStopTrackingTouch(seekBar); - setupVideoControlsToggler(); - } - - @Override protected void onBufferStart() { progressIndicator.setVisibility(View.VISIBLE); } - @Override protected void onBufferEnd() { progressIndicator.setVisibility(View.INVISIBLE); } @@ -395,9 +644,7 @@ public class VideoplayerActivity extends MediaplayerActivity { hideVideoControls(true); } - @Override - protected void setScreenOn(boolean enable) { - super.setScreenOn(enable); + private void setScreenOn(boolean enable) { if (enable) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } else { @@ -405,9 +652,58 @@ public class VideoplayerActivity extends MediaplayerActivity { } } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + onPositionObserverUpdate(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPlaybackServiceChanged(ServiceEvent event) { + if (event.action == ServiceEvent.Action.SERVICE_SHUT_DOWN) { + finish(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + requestCastButton(menu); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.mediaplayer, menu); + return true; + } + @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); + if (controller == null) { + return false; + } + Playable media = controller.getMedia(); + boolean isFeedMedia = (media instanceof FeedMedia); + + menu.findItem(R.id.open_feed_item).setVisible(isFeedMedia); // FeedMedia implies it belongs to a Feed + + boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null ); + menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink); + + boolean isItemAndHasLink = isFeedMedia && + ShareUtils.hasLinkToShare(((FeedMedia) media).getItem()); + + boolean isItemHasDownloadLink = isFeedMedia && ((FeedMedia) media).getDownload_url() != null; + + menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink); + + menu.findItem(R.id.add_to_favorites_item).setVisible(false); + menu.findItem(R.id.remove_from_favorites_item).setVisible(false); + if (isFeedMedia) { + menu.findItem(R.id.add_to_favorites_item).setVisible(!isFavorite); + menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite); + } + + menu.findItem(R.id.set_sleeptimer_item).setVisible(!controller.sleepTimerActive()); + menu.findItem(R.id.disable_sleeptimer_item).setVisible(controller.sleepTimerActive()); + if (PictureInPictureUtil.supportsPictureInPicture(this)) { menu.findItem(R.id.player_go_to_picture_in_picture).setVisible(true); } @@ -421,7 +717,190 @@ public class VideoplayerActivity extends MediaplayerActivity { compatEnterPictureInPicture(); return true; } - return super.onOptionsItemSelected(item); + if (controller == null) { + return false; + } + Playable media = controller.getMedia(); + if (item.getItemId() == android.R.id.home) { + Intent intent = new Intent(VideoplayerActivity.this, + MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP + | Intent.FLAG_ACTIVITY_NEW_TASK); + + View cover = findViewById(R.id.imgvCover); + if (cover != null) { + ActivityOptionsCompat options = ActivityOptionsCompat + .makeSceneTransitionAnimation(VideoplayerActivity.this, cover, "coverTransition"); + startActivity(intent, options.toBundle()); + } else { + startActivity(intent); + } + finish(); + return true; + } else { + if (media != null) { + final @Nullable FeedItem feedItem = getFeedItem(media); // some options option requires FeedItem + switch (item.getItemId()) { + case R.id.add_to_favorites_item: + if (feedItem != null) { + DBWriter.addFavoriteItem(feedItem); + isFavorite = true; + invalidateOptionsMenu(); + } + break; + case R.id.remove_from_favorites_item: + if (feedItem != null) { + DBWriter.removeFavoriteItem(feedItem); + isFavorite = false; + invalidateOptionsMenu(); + } + break; + case R.id.disable_sleeptimer_item: // Fall-through + case R.id.set_sleeptimer_item: + new SleepTimerDialog().show(getSupportFragmentManager(), "SleepTimerDialog"); + break; + case R.id.audio_controls: + PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(); + dialog.show(getSupportFragmentManager(), "playback_controls"); + break; + case R.id.open_feed_item: + if (feedItem != null) { + Intent intent = MainActivity.getIntentToOpenFeed(this, feedItem.getFeedId()); + startActivity(intent); + } + break; + case R.id.visit_website_item: + IntentUtils.openInBrowser(VideoplayerActivity.this, getWebsiteLinkWithFallback(media)); + break; + case R.id.share_item: + if (feedItem != null) { + ShareDialog shareDialog = ShareDialog.newInstance(feedItem); + shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog"); + } + break; + default: + return false; + } + return true; + } else { + return false; + } + } + } + + private static String getWebsiteLinkWithFallback(Playable media) { + if (media == null) { + return null; + } else if (StringUtils.isNotBlank(media.getWebsiteLink())) { + return media.getWebsiteLink(); + } else if (media instanceof FeedMedia) { + return FeedItemUtil.getLinkWithFallback(((FeedMedia)media).getItem()); + } + return null; + } + + void onPositionObserverUpdate() { + if (controller == null || txtvPosition == null || txtvLength == null) { + return; + } + + TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); + int currentPosition = converter.convert(controller.getPosition()); + int duration = converter.convert(controller.getDuration()); + int remainingTime = converter.convert( + controller.getDuration() - controller.getPosition()); + Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition)); + if (currentPosition == PlaybackService.INVALID_TIME || + duration == PlaybackService.INVALID_TIME) { + Log.w(TAG, "Could not react to position observer update because of invalid time"); + return; + } + txtvPosition.setText(Converter.getDurationStringLong(currentPosition)); + if (showTimeLeft) { + txtvLength.setText("-" + Converter.getDurationStringLong(remainingTime)); + } else { + txtvLength.setText(Converter.getDurationStringLong(duration)); + } + updateProgressbarPosition(currentPosition, duration); + } + + private void updateProgressbarPosition(int position, int duration) { + Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")"); + if(sbPosition == null) { + return; + } + float progress = ((float) position) / duration; + sbPosition.setProgress((int) (progress * sbPosition.getMax())); + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (controller == null || txtvLength == null) { + return; + } + if (fromUser) { + prog = progress / ((float) seekBar.getMax()); + TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); + int position = converter.convert((int) (prog * controller.getDuration())); + txtvSeek.setText(Converter.getDurationStringLong(position)); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + cardViewSeek.setScaleX(.8f); + cardViewSeek.setScaleY(.8f); + cardViewSeek.animate() + .setInterpolator(new FastOutSlowInInterpolator()) + .alpha(1f).scaleX(1f).scaleY(1f) + .setDuration(200) + .start(); + videoControlsHider.stop(); + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + if (controller != null) { + controller.seekTo((int) (prog * controller.getDuration())); + } + cardViewSeek.setScaleX(1f); + cardViewSeek.setScaleY(1f); + cardViewSeek.animate() + .setInterpolator(new FastOutSlowInInterpolator()) + .alpha(0f).scaleX(.8f).scaleY(.8f) + .setDuration(200) + .start(); + setupVideoControlsToggler(); + } + + private void checkFavorite() { + FeedItem feedItem = getFeedItem(controller.getMedia()); + if (feedItem == null) { + return; + } + if (disposable != null) { + disposable.dispose(); + } + disposable = Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId())) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + item -> { + boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE); + if (isFavorite != isFav) { + isFavorite = isFav; + invalidateOptionsMenu(); + } + }, error -> Log.e(TAG, Log.getStackTraceString(error))); + } + + @Nullable + private static FeedItem getFeedItem(@Nullable Playable playable) { + if (playable instanceof FeedMedia) { + return ((FeedMedia) playable).getItem(); + } else { + return null; + } } private void compatEnterPictureInPicture() { From 33ad1a91f0c125bb999642167a931f9a05b3384b Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 14 May 2021 21:44:59 +0200 Subject: [PATCH 3/5] Remove unneccessary method call chaining --- .../activity/VideoplayerActivity.java | 60 ++++++------------- 1 file changed, 17 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index dc4345c21..4572cf1c4 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -230,12 +230,12 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. @Override public void onBufferStart() { - VideoplayerActivity.this.onBufferStart(); + progressIndicator.setVisibility(View.VISIBLE); } @Override public void onBufferEnd() { - VideoplayerActivity.this.onBufferEnd(); + progressIndicator.setVisibility(View.INVISIBLE); } @Override @@ -247,7 +247,11 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. @Override public void handleError(int code) { - VideoplayerActivity.this.handleError(code); + final AlertDialog.Builder errorDialog = new AlertDialog.Builder(VideoplayerActivity.this); + errorDialog.setTitle(R.string.error_label); + errorDialog.setMessage(MediaPlayerError.getErrorString(VideoplayerActivity.this, code)); + errorDialog.setNeutralButton(android.R.string.ok, (dialog, which) -> finish()); + errorDialog.show(); } @Override @@ -272,7 +276,11 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. @Override public void onAwaitingVideoSurface() { - VideoplayerActivity.this.onAwaitingVideoSurface(); + setupVideoAspectRatio(); + if (videoSurfaceCreated && controller != null) { + Log.d(TAG, "Videosurface already created, setting videosurface now"); + controller.setVideoSurface(videoview.getHolder()); + } } @Override @@ -282,8 +290,11 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. @Override protected void setScreenOn(boolean enable) { - super.setScreenOn(enable); - VideoplayerActivity.this.setScreenOn(enable); + if (enable) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } else { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } } }; } @@ -408,14 +419,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. videoview.setAvailableSize(videoframe.getWidth(), videoframe.getHeight())); } - protected void onAwaitingVideoSurface() { - setupVideoAspectRatio(); - if (videoSurfaceCreated && controller != null) { - Log.d(TAG, "Videosurface already created, setting videosurface now"); - controller.setVideoSurface(videoview.getHolder()); - } - } - private final View.OnTouchListener onVideoviewTouched = (v, event) -> { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (PictureInPictureUtil.isInPictureInPictureMode(this)) { @@ -544,19 +547,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. setupVideoControlsToggler(); } - private void handleError(int errorCode) { - final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this); - errorDialog.setTitle(R.string.error_label); - errorDialog.setMessage(MediaPlayerError.getErrorString(this, errorCode)); - errorDialog.setNeutralButton("OK", - (dialog, which) -> { - dialog.dismiss(); - finish(); - } - ); - errorDialog.create().show(); - } - private final SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() { @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, @@ -602,14 +592,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. } } - protected void onBufferStart() { - progressIndicator.setVisibility(View.VISIBLE); - } - - protected void onBufferEnd() { - progressIndicator.setVisibility(View.INVISIBLE); - } - @SuppressLint("NewApi") private void showVideoControls() { videoOverlay.setVisibility(View.VISIBLE); @@ -644,14 +626,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. hideVideoControls(true); } - private void setScreenOn(boolean enable) { - if (enable) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } else { - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - } - @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(PlaybackPositionEvent event) { onPositionObserverUpdate(); From ac0580400ed1c8f8025df9e7fd0d12d892aafac9 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 14 May 2021 22:07:28 +0200 Subject: [PATCH 4/5] Switched video player to ViewBinding --- .../ui/VideoplayerActivityTest.java | 2 +- .../activity/VideoplayerActivity.java | 285 +++++++----------- .../main/res/layout/videoplayer_activity.xml | 35 ++- 3 files changed, 121 insertions(+), 201 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java b/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java index ab16d7603..0dae22db1 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java @@ -31,6 +31,6 @@ public class VideoplayerActivityTest { @Test public void testStartActivity() throws Exception { activityTestRule.launchActivity(new Intent()); - onView(withId(R.id.videoframe)).check(matches(isDisplayed())); + onView(withId(R.id.videoPlayerContainer)).check(matches(isDisplayed())); } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index 4572cf1c4..1cdf45982 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -9,42 +9,31 @@ import android.media.AudioManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.MenuInflater; -import android.view.animation.AlphaAnimation; -import android.view.animation.AnimationSet; -import android.view.animation.ScaleAnimation; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ImageView; - -import android.widget.TextView; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.cardview.widget.CardView; -import androidx.core.app.ActivityOptionsCompat; -import androidx.core.view.WindowCompat; -import androidx.appcompat.app.ActionBar; import android.util.Log; import android.util.Pair; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.LayoutInflater; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.View; import android.view.WindowManager; +import android.view.animation.AlphaAnimation; import android.view.animation.Animation; +import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; +import android.view.animation.ScaleAnimation; +import android.widget.EditText; import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.ProgressBar; import android.widget.SeekBar; - -import java.lang.ref.WeakReference; -import java.text.NumberFormat; -import java.util.concurrent.atomic.AtomicBoolean; - +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.core.app.ActivityOptionsCompat; +import androidx.core.view.WindowCompat; import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import com.bumptech.glide.Glide; import de.danoeh.antennapod.R; @@ -64,6 +53,7 @@ import de.danoeh.antennapod.core.util.TimeSpeedConverter; import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil; import de.danoeh.antennapod.core.util.playback.MediaPlayerError; import de.danoeh.antennapod.core.util.playback.PlaybackController; +import de.danoeh.antennapod.databinding.VideoplayerActivityBinding; import de.danoeh.antennapod.dialog.PlaybackControlsDialog; import de.danoeh.antennapod.dialog.ShareDialog; import de.danoeh.antennapod.dialog.SkipPreferenceDialog; @@ -72,8 +62,6 @@ import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.model.playback.Playable; import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter; -import de.danoeh.antennapod.view.AspectRatioVideoView; -import de.danoeh.antennapod.view.PlayButton; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; @@ -83,6 +71,8 @@ import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import java.lang.ref.WeakReference; + /** * Activity for playing video files. */ @@ -96,29 +86,8 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. private boolean videoSurfaceCreated = false; private boolean destroyingDueToReload = false; private long lastScreenTap = 0; - private VideoControlsHider videoControlsHider = new VideoControlsHider(this); - - private final AtomicBoolean isSetup = new AtomicBoolean(false); - - private LinearLayout controls; - private LinearLayout videoOverlay; - private AspectRatioVideoView videoview; - private ProgressBar progressIndicator; - private FrameLayout videoframe; - private ImageView skipAnimationView; - private TextView txtvPosition; - private TextView txtvLength; - private SeekBar sbPosition; - private ImageButton butRev; - private TextView txtvRev; - private PlayButton butPlay; - private ImageButton butFF; - private TextView txtvFF; - private ImageButton butSkip; - private CardView cardViewSeek; - private TextView txtvSeek; - + private VideoplayerActivityBinding viewBinding; private PlaybackController controller; private boolean showTimeLeft = false; private boolean isFavorite = false; @@ -138,8 +107,11 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. StorageUtils.checkStorageAvailability(this); getWindow().setFormat(PixelFormat.TRANSPARENT); + viewBinding = VideoplayerActivityBinding.inflate(LayoutInflater.from(this)); + setContentView(viewBinding.getRoot()); setupGUI(); getSupportActionBar().setBackgroundDrawable(new ColorDrawable(0x80000000)); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); } @Override @@ -170,7 +142,8 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. if (!PictureInPictureUtil.isInPictureInPictureMode(this)) { videoControlsHider.stop(); } - progressIndicator.setVisibility(View.GONE); // Controller released; we will not receive buffering updates + // Controller released; we will not receive buffering updates + viewBinding.progressBar.setVisibility(View.GONE); } @Override @@ -230,19 +203,17 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. @Override public void onBufferStart() { - progressIndicator.setVisibility(View.VISIBLE); + viewBinding.progressBar.setVisibility(View.VISIBLE); } @Override public void onBufferEnd() { - progressIndicator.setVisibility(View.INVISIBLE); + viewBinding.progressBar.setVisibility(View.INVISIBLE); } @Override public void onBufferUpdate(float progress) { - if (sbPosition != null) { - sbPosition.setSecondaryProgress((int) (progress * sbPosition.getMax())); - } + viewBinding.sbPosition.setSecondaryProgress((int) (progress * viewBinding.sbPosition.getMax())); } @Override @@ -266,7 +237,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. @Override protected void updatePlayButtonShowsPlay(boolean showPlay) { - butPlay.setIsShowPlay(showPlay); + viewBinding.playButton.setIsShowPlay(showPlay); } @Override @@ -279,7 +250,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. setupVideoAspectRatio(); if (videoSurfaceCreated && controller != null) { Log.d(TAG, "Videosurface already created, setting videosurface now"); - controller.setVideoSurface(videoview.getHolder()); + controller.setVideoSurface(viewBinding.videoView.getHolder()); } } @@ -315,108 +286,61 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. } protected void setupGUI() { - if (isSetup.getAndSet(true)) { - return; - } - setContentView(R.layout.videoplayer_activity); - sbPosition = findViewById(R.id.sbPosition); - txtvPosition = findViewById(R.id.txtvPosition); - cardViewSeek = findViewById(R.id.cardViewSeek); - txtvSeek = findViewById(R.id.txtvSeek); - showTimeLeft = UserPreferences.shouldShowRemainingTime(); Log.d("timeleft", showTimeLeft ? "true" : "false"); - txtvLength = findViewById(R.id.txtvLength); - if (txtvLength != null) { - txtvLength.setOnClickListener(v -> { - showTimeLeft = !showTimeLeft; - Playable media = controller.getMedia(); - if (media == null) { - return; - } + viewBinding.durationLabel.setOnClickListener(v -> { + showTimeLeft = !showTimeLeft; + Playable media = controller.getMedia(); + if (media == null) { + return; + } - TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); - String length; - if (showTimeLeft) { - int remainingTime = converter.convert( - media.getDuration() - media.getPosition()); + TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); + String length; + if (showTimeLeft) { + int remainingTime = converter.convert( + media.getDuration() - media.getPosition()); - length = "-" + Converter.getDurationStringLong(remainingTime); - } else { - int duration = converter.convert(media.getDuration()); - length = Converter.getDurationStringLong(duration); - } - txtvLength.setText(length); + length = "-" + Converter.getDurationStringLong(remainingTime); + } else { + int duration = converter.convert(media.getDuration()); + length = Converter.getDurationStringLong(duration); + } + viewBinding.durationLabel.setText(length); - UserPreferences.setShowRemainTimeSetting(showTimeLeft); - Log.d("timeleft on click", showTimeLeft ? "true" : "false"); - }); - } + UserPreferences.setShowRemainTimeSetting(showTimeLeft); + Log.d("timeleft on click", showTimeLeft ? "true" : "false"); + }); - butRev = findViewById(R.id.butRev); - txtvRev = findViewById(R.id.txtvRev); - if (txtvRev != null) { - txtvRev.setText(NumberFormat.getInstance().format(UserPreferences.getRewindSecs())); - } - butPlay = findViewById(R.id.butPlay); - butPlay.setIsVideoScreen(true); - butFF = findViewById(R.id.butFF); - txtvFF = findViewById(R.id.txtvFF); - if (txtvFF != null) { - txtvFF.setText(NumberFormat.getInstance().format(UserPreferences.getFastForwardSecs())); - } - butSkip = findViewById(R.id.butSkip); - - // SEEKBAR SETUP - - sbPosition.setOnSeekBarChangeListener(this); - - // BUTTON SETUP - - if (butRev != null) { - butRev.setOnClickListener(v -> onRewind()); - butRev.setOnLongClickListener(v -> { - SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this, - SkipPreferenceDialog.SkipDirection.SKIP_REWIND, txtvRev); - return true; - }); - } - - butPlay.setOnClickListener(v -> onPlayPause()); - - if (butFF != null) { - butFF.setOnClickListener(v -> onFastForward()); - butFF.setOnLongClickListener(v -> { - SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this, - SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, txtvFF); - return false; - }); - } - - if (butSkip != null) { - butSkip.setOnClickListener(v -> - IntentUtils.sendLocalBroadcast(VideoplayerActivity.this, PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); - } - - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - controls = findViewById(R.id.controls); - videoOverlay = findViewById(R.id.overlay); - videoview = findViewById(R.id.videoview); - videoframe = findViewById(R.id.videoframe); - progressIndicator = findViewById(R.id.progressIndicator); - skipAnimationView = findViewById(R.id.skip_animation); - videoview.getHolder().addCallback(surfaceHolderCallback); - videoframe.setOnTouchListener(onVideoviewTouched); - videoOverlay.setOnTouchListener((view, motionEvent) -> true); // To suppress touches directly below the slider - videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - videoOverlay.setFitsSystemWindows(true); + viewBinding.sbPosition.setOnSeekBarChangeListener(this); + viewBinding.rewindButton.setOnClickListener(v -> onRewind()); + viewBinding.rewindButton.setOnLongClickListener(v -> { + SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this, + SkipPreferenceDialog.SkipDirection.SKIP_REWIND, null); + return true; + }); + viewBinding.playButton.setIsVideoScreen(true); + viewBinding.playButton.setOnClickListener(v -> onPlayPause()); + viewBinding.fastForwardButton.setOnClickListener(v -> onFastForward()); + viewBinding.fastForwardButton.setOnLongClickListener(v -> { + SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this, + SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, null); + return false; + }); + // To suppress touches directly below the slider + viewBinding.bottomControlsContainer.setOnTouchListener((view, motionEvent) -> true); + viewBinding.bottomControlsContainer.setFitsSystemWindows(true); + viewBinding.videoView.getHolder().addCallback(surfaceHolderCallback); + viewBinding.videoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); setupVideoControlsToggler(); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - videoframe.getViewTreeObserver().addOnGlobalLayoutListener(() -> - videoview.setAvailableSize(videoframe.getWidth(), videoframe.getHeight())); + viewBinding.videoPlayerContainer.setOnTouchListener(onVideoviewTouched); + viewBinding.videoPlayerContainer.getViewTreeObserver().addOnGlobalLayoutListener(() -> + viewBinding.videoView.setAvailableSize( + viewBinding.videoPlayerContainer.getWidth(), viewBinding.videoPlayerContainer.getHeight())); } private final View.OnTouchListener onVideoviewTouched = (v, event) -> { @@ -462,18 +386,18 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. skipAnimation.setFillAfter(false); skipAnimation.setDuration(800); - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) skipAnimationView.getLayoutParams(); + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) viewBinding.skipAnimationImage.getLayoutParams(); if (isForward) { - skipAnimationView.setImageResource(R.drawable.ic_fast_forward_video_white); + viewBinding.skipAnimationImage.setImageResource(R.drawable.ic_fast_forward_video_white); params.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; } else { - skipAnimationView.setImageResource(R.drawable.ic_fast_rewind_video_white); + viewBinding.skipAnimationImage.setImageResource(R.drawable.ic_fast_rewind_video_white); params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; } - skipAnimationView.setVisibility(View.VISIBLE); - skipAnimationView.setLayoutParams(params); - skipAnimationView.startAnimation(skipAnimation); + viewBinding.skipAnimationImage.setVisibility(View.VISIBLE); + viewBinding.skipAnimationImage.setLayoutParams(params); + viewBinding.skipAnimationImage.startAnimation(skipAnimation); skipAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { @@ -481,7 +405,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. @Override public void onAnimationEnd(Animation animation) { - skipAnimationView.setVisibility(View.GONE); + viewBinding.skipAnimationImage.setVisibility(View.GONE); } @Override @@ -502,7 +426,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. Pair videoSize = controller.getVideoSize(); if (videoSize != null && videoSize.first > 0 && videoSize.second > 0) { Log.d(TAG, "Width,height of video: " + videoSize.first + ", " + videoSize.second); - videoview.setVideoSize(videoSize.first, videoSize.second); + viewBinding.videoView.setVideoSize(videoSize.first, videoSize.second); } else { Log.e(TAG, "Could not determine video size"); } @@ -530,7 +454,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. } void onPlayPause() { - if(controller == null) { + if (controller == null) { return; } controller.init(); @@ -594,14 +518,14 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. @SuppressLint("NewApi") private void showVideoControls() { - videoOverlay.setVisibility(View.VISIBLE); - controls.setVisibility(View.VISIBLE); + viewBinding.bottomControlsContainer.setVisibility(View.VISIBLE); + viewBinding.controlsContainer.setVisibility(View.VISIBLE); final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_in); if (animation != null) { - videoOverlay.startAnimation(animation); - controls.startAnimation(animation); + viewBinding.bottomControlsContainer.startAnimation(animation); + viewBinding.controlsContainer.startAnimation(animation); } - videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + viewBinding.videoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); } @SuppressLint("NewApi") @@ -609,17 +533,17 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. if (showAnimation) { final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out); if (animation != null) { - videoOverlay.startAnimation(animation); - controls.startAnimation(animation); + viewBinding.bottomControlsContainer.startAnimation(animation); + viewBinding.controlsContainer.startAnimation(animation); } } getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - videoOverlay.setFitsSystemWindows(true); + viewBinding.bottomControlsContainer.setFitsSystemWindows(true); - videoOverlay.setVisibility(View.GONE); - controls.setVisibility(View.GONE); + viewBinding.bottomControlsContainer.setVisibility(View.GONE); + viewBinding.controlsContainer.setVisibility(View.GONE); } private void hideVideoControls() { @@ -774,7 +698,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. } void onPositionObserverUpdate() { - if (controller == null || txtvPosition == null || txtvLength == null) { + if (controller == null) { return; } @@ -789,42 +713,39 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. Log.w(TAG, "Could not react to position observer update because of invalid time"); return; } - txtvPosition.setText(Converter.getDurationStringLong(currentPosition)); + viewBinding.positionLabel.setText(Converter.getDurationStringLong(currentPosition)); if (showTimeLeft) { - txtvLength.setText("-" + Converter.getDurationStringLong(remainingTime)); + viewBinding.durationLabel.setText("-" + Converter.getDurationStringLong(remainingTime)); } else { - txtvLength.setText(Converter.getDurationStringLong(duration)); + viewBinding.durationLabel.setText(Converter.getDurationStringLong(duration)); } updateProgressbarPosition(currentPosition, duration); } private void updateProgressbarPosition(int position, int duration) { Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")"); - if(sbPosition == null) { - return; - } float progress = ((float) position) / duration; - sbPosition.setProgress((int) (progress * sbPosition.getMax())); + viewBinding.sbPosition.setProgress((int) (progress * viewBinding.sbPosition.getMax())); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (controller == null || txtvLength == null) { + if (controller == null) { return; } if (fromUser) { prog = progress / ((float) seekBar.getMax()); TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); int position = converter.convert((int) (prog * controller.getDuration())); - txtvSeek.setText(Converter.getDurationStringLong(position)); + viewBinding.seekPositionLabel.setText(Converter.getDurationStringLong(position)); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { - cardViewSeek.setScaleX(.8f); - cardViewSeek.setScaleY(.8f); - cardViewSeek.animate() + viewBinding.seekCardView.setScaleX(.8f); + viewBinding.seekCardView.setScaleY(.8f); + viewBinding.seekCardView.animate() .setInterpolator(new FastOutSlowInInterpolator()) .alpha(1f).scaleX(1f).scaleY(1f) .setDuration(200) @@ -837,9 +758,9 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. if (controller != null) { controller.seekTo((int) (prog * controller.getDuration())); } - cardViewSeek.setScaleX(1f); - cardViewSeek.setScaleY(1f); - cardViewSeek.animate() + viewBinding.seekCardView.setScaleX(1f); + viewBinding.seekCardView.setScaleY(1f); + viewBinding.seekCardView.animate() .setInterpolator(new FastOutSlowInInterpolator()) .alpha(0f).scaleX(.8f).scaleY(.8f) .setDuration(200) diff --git a/app/src/main/res/layout/videoplayer_activity.xml b/app/src/main/res/layout/videoplayer_activity.xml index f5a163849..fcc1c5f15 100644 --- a/app/src/main/res/layout/videoplayer_activity.xml +++ b/app/src/main/res/layout/videoplayer_activity.xml @@ -6,16 +6,16 @@ xmlns:tools="http://schemas.android.com/tools" android:background="@color/black" android:orientation="vertical" - android:id="@+id/videoframe"> + android:id="@+id/videoPlayerContainer"> From 3eae21db27e73b0bfab0bc3807f65211aab86315 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 14 May 2021 22:24:14 +0200 Subject: [PATCH 5/5] Clean up some lint errors --- .../activity/VideoplayerActivity.java | 266 +++++++----------- 1 file changed, 94 insertions(+), 172 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index 1cdf45982..d436acf0d 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -9,6 +9,7 @@ import android.media.AudioManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.util.Pair; import android.view.Gravity; @@ -30,9 +31,7 @@ import android.widget.EditText; import android.widget.FrameLayout; import android.widget.SeekBar; import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; -import androidx.core.app.ActivityOptionsCompat; import androidx.core.view.WindowCompat; import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import com.bumptech.glide.Glide; @@ -71,8 +70,6 @@ import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; -import java.lang.ref.WeakReference; - /** * Activity for playing video files. */ @@ -86,7 +83,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. private boolean videoSurfaceCreated = false; private boolean destroyingDueToReload = false; private long lastScreenTap = 0; - private VideoControlsHider videoControlsHider = new VideoControlsHider(this); + private Handler videoControlsHider = new Handler(Looper.getMainLooper()); private VideoplayerActivityBinding viewBinding; private PlaybackController controller; private boolean showTimeLeft = false; @@ -99,7 +96,8 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. protected void onCreate(Bundle savedInstanceState) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); - supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY); // has to be called before setting layout content + // has to be called before setting layout content + supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY); setTheme(R.style.Theme_AntennaPod_VideoPlayer); super.onCreate(savedInstanceState); @@ -109,7 +107,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. getWindow().setFormat(PixelFormat.TRANSPARENT); viewBinding = VideoplayerActivityBinding.inflate(LayoutInflater.from(this)); setContentView(viewBinding.getRoot()); - setupGUI(); + setupView(); getSupportActionBar().setBackgroundDrawable(new ColorDrawable(0x80000000)); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } @@ -140,7 +138,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. EventBus.getDefault().unregister(this); super.onStop(); if (!PictureInPictureUtil.isInPictureInPictureMode(this)) { - videoControlsHider.stop(); + videoControlsHider.removeCallbacks(hideVideoControls); } // Controller released; we will not receive buffering updates viewBinding.progressBar.setVisibility(View.GONE); @@ -174,13 +172,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. super.onPause(); } - @Override - protected void onDestroy() { - videoControlsHider.stop(); - videoControlsHider = null; - super.onDestroy(); - } - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void onTrimMemory(int level) { @@ -285,7 +276,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. } } - protected void setupGUI() { + protected void setupView() { showTimeLeft = UserPreferences.shouldShowRemainingTime(); Log.d("timeleft", showTimeLeft ? "true" : "false"); viewBinding.durationLabel.setOnClickListener(v -> { @@ -298,9 +289,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier()); String length; if (showTimeLeft) { - int remainingTime = converter.convert( - media.getDuration() - media.getPosition()); - + int remainingTime = converter.convert(media.getDuration() - media.getPosition()); length = "-" + Converter.getDurationStringLong(remainingTime); } else { int duration = converter.convert(media.getDuration()); @@ -343,39 +332,47 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. viewBinding.videoPlayerContainer.getWidth(), viewBinding.videoPlayerContainer.getHeight())); } + private final Runnable hideVideoControls = () -> { + if (videoControlsShowing) { + Log.d(TAG, "Hiding video controls"); + getSupportActionBar().hide(); + hideVideoControls(true); + videoControlsShowing = false; + } + }; + private final View.OnTouchListener onVideoviewTouched = (v, event) -> { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (PictureInPictureUtil.isInPictureInPictureMode(this)) { - return true; - } - videoControlsHider.stop(); - - if (System.currentTimeMillis() - lastScreenTap < 300) { - if (event.getX() > v.getMeasuredWidth() / 2.0f) { - onFastForward(); - showSkipAnimation(true); - } else { - onRewind(); - showSkipAnimation(false); - } - if (videoControlsShowing) { - getSupportActionBar().hide(); - hideVideoControls(false); - videoControlsShowing = false; - } - return true; - } - - toggleVideoControlsVisibility(); - if (videoControlsShowing) { - setupVideoControlsToggler(); - } - - lastScreenTap = System.currentTimeMillis(); - return true; - } else { + if (event.getAction() != MotionEvent.ACTION_DOWN) { return false; } + if (PictureInPictureUtil.isInPictureInPictureMode(this)) { + return true; + } + videoControlsHider.removeCallbacks(hideVideoControls); + + if (System.currentTimeMillis() - lastScreenTap < 300) { + if (event.getX() > v.getMeasuredWidth() / 2.0f) { + onFastForward(); + showSkipAnimation(true); + } else { + onRewind(); + showSkipAnimation(false); + } + if (videoControlsShowing) { + getSupportActionBar().hide(); + hideVideoControls(false); + videoControlsShowing = false; + } + return true; + } + + toggleVideoControlsVisibility(); + if (videoControlsShowing) { + setupVideoControlsToggler(); + } + + lastScreenTap = System.currentTimeMillis(); + return true; }; private void showSkipAnimation(boolean isForward) { @@ -415,10 +412,9 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. }); } - @SuppressLint("NewApi") private void setupVideoControlsToggler() { - videoControlsHider.stop(); - videoControlsHider.start(); + videoControlsHider.removeCallbacks(hideVideoControls); + videoControlsHider.postDelayed(hideVideoControls, 2500); } private void setupVideoAspectRatio() { @@ -436,7 +432,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. private void toggleVideoControlsVisibility() { if (videoControlsShowing) { getSupportActionBar().hide(); - hideVideoControls(); + hideVideoControls(true); } else { getSupportActionBar().show(); showVideoControls(); @@ -457,7 +453,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. if (controller == null) { return; } - controller.init(); controller.playPause(); setupVideoControlsToggler(); } @@ -473,8 +468,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. private final SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() { @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, - int height) { + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { holder.setFixedSize(width, height); } @@ -516,7 +510,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. } } - @SuppressLint("NewApi") private void showVideoControls() { viewBinding.bottomControlsContainer.setVisibility(View.VISIBLE); viewBinding.controlsContainer.setVisibility(View.VISIBLE); @@ -528,7 +521,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. viewBinding.videoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); } - @SuppressLint("NewApi") private void hideVideoControls(boolean showAnimation) { if (showAnimation) { final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out); @@ -546,10 +538,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. viewBinding.controlsContainer.setVisibility(View.GONE); } - private void hideVideoControls() { - hideVideoControls(true); - } - @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(PlaybackPositionEvent event) { onPositionObserverUpdate(); @@ -582,14 +570,11 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. menu.findItem(R.id.open_feed_item).setVisible(isFeedMedia); // FeedMedia implies it belongs to a Feed - boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null ); + boolean hasWebsiteLink = getWebsiteLinkWithFallback(media) != null; menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink); - boolean isItemAndHasLink = isFeedMedia && - ShareUtils.hasLinkToShare(((FeedMedia) media).getItem()); - + boolean isItemAndHasLink = isFeedMedia && ShareUtils.hasLinkToShare(((FeedMedia) media).getItem()); boolean isItemHasDownloadLink = isFeedMedia && ((FeedMedia) media).getDownload_url() != null; - menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink); menu.findItem(R.id.add_to_favorites_item).setVisible(false); @@ -615,75 +600,49 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. compatEnterPictureInPicture(); return true; } + if (item.getItemId() == android.R.id.home) { + Intent intent = new Intent(VideoplayerActivity.this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finish(); + return true; + } + if (controller == null) { return false; } - Playable media = controller.getMedia(); - if (item.getItemId() == android.R.id.home) { - Intent intent = new Intent(VideoplayerActivity.this, - MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP - | Intent.FLAG_ACTIVITY_NEW_TASK); - View cover = findViewById(R.id.imgvCover); - if (cover != null) { - ActivityOptionsCompat options = ActivityOptionsCompat - .makeSceneTransitionAnimation(VideoplayerActivity.this, cover, "coverTransition"); - startActivity(intent, options.toBundle()); - } else { - startActivity(intent); - } - finish(); - return true; - } else { - if (media != null) { - final @Nullable FeedItem feedItem = getFeedItem(media); // some options option requires FeedItem - switch (item.getItemId()) { - case R.id.add_to_favorites_item: - if (feedItem != null) { - DBWriter.addFavoriteItem(feedItem); - isFavorite = true; - invalidateOptionsMenu(); - } - break; - case R.id.remove_from_favorites_item: - if (feedItem != null) { - DBWriter.removeFavoriteItem(feedItem); - isFavorite = false; - invalidateOptionsMenu(); - } - break; - case R.id.disable_sleeptimer_item: // Fall-through - case R.id.set_sleeptimer_item: - new SleepTimerDialog().show(getSupportFragmentManager(), "SleepTimerDialog"); - break; - case R.id.audio_controls: - PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(); - dialog.show(getSupportFragmentManager(), "playback_controls"); - break; - case R.id.open_feed_item: - if (feedItem != null) { - Intent intent = MainActivity.getIntentToOpenFeed(this, feedItem.getFeedId()); - startActivity(intent); - } - break; - case R.id.visit_website_item: - IntentUtils.openInBrowser(VideoplayerActivity.this, getWebsiteLinkWithFallback(media)); - break; - case R.id.share_item: - if (feedItem != null) { - ShareDialog shareDialog = ShareDialog.newInstance(feedItem); - shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog"); - } - break; - default: - return false; - } - return true; - } else { - return false; - } + Playable media = controller.getMedia(); + if (media == null) { + return false; } + final @Nullable FeedItem feedItem = getFeedItem(media); // some options option requires FeedItem + if (item.getItemId() == R.id.add_to_favorites_item && feedItem != null) { + DBWriter.addFavoriteItem(feedItem); + isFavorite = true; + invalidateOptionsMenu(); + } else if (item.getItemId() == R.id.remove_from_favorites_item && feedItem != null) { + DBWriter.removeFavoriteItem(feedItem); + isFavorite = false; + invalidateOptionsMenu(); + } else if (item.getItemId() == R.id.disable_sleeptimer_item + || item.getItemId() == R.id.set_sleeptimer_item) { + new SleepTimerDialog().show(getSupportFragmentManager(), "SleepTimerDialog"); + } else if (item.getItemId() == R.id.audio_controls) { + PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(); + dialog.show(getSupportFragmentManager(), "playback_controls"); + } else if (item.getItemId() == R.id.open_feed_item && feedItem != null) { + Intent intent = MainActivity.getIntentToOpenFeed(this, feedItem.getFeedId()); + startActivity(intent); + } else if (item.getItemId() == R.id.visit_website_item) { + IntentUtils.openInBrowser(VideoplayerActivity.this, getWebsiteLinkWithFallback(media)); + } else if (item.getItemId() == R.id.share_item && feedItem != null) { + ShareDialog shareDialog = ShareDialog.newInstance(feedItem); + shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog"); + } else { + return false; + } + return true; } private static String getWebsiteLinkWithFallback(Playable media) { @@ -692,7 +651,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. } else if (StringUtils.isNotBlank(media.getWebsiteLink())) { return media.getWebsiteLink(); } else if (media instanceof FeedMedia) { - return FeedItemUtil.getLinkWithFallback(((FeedMedia)media).getItem()); + return FeedItemUtil.getLinkWithFallback(((FeedMedia) media).getItem()); } return null; } @@ -708,8 +667,8 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. int remainingTime = converter.convert( controller.getDuration() - controller.getPosition()); Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition)); - if (currentPosition == PlaybackService.INVALID_TIME || - duration == PlaybackService.INVALID_TIME) { + if (currentPosition == PlaybackService.INVALID_TIME + || duration == PlaybackService.INVALID_TIME) { Log.w(TAG, "Could not react to position observer update because of invalid time"); return; } @@ -750,7 +709,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. .alpha(1f).scaleX(1f).scaleY(1f) .setDuration(200) .start(); - videoControlsHider.stop(); + videoControlsHider.removeCallbacks(hideVideoControls); } @Override @@ -806,43 +765,6 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. } } - private static class VideoControlsHider extends Handler { - - private static final int DELAY = 2500; - - private WeakReference activity; - - VideoControlsHider(VideoplayerActivity activity) { - this.activity = new WeakReference<>(activity); - } - - private final Runnable hideVideoControls = () -> { - VideoplayerActivity vpa = activity != null ? activity.get() : null; - if (vpa == null) { - return; - } - if (vpa.videoControlsShowing) { - Log.d(TAG, "Hiding video controls"); - ActionBar actionBar = vpa.getSupportActionBar(); - if (actionBar != null) { - actionBar.hide(); - } - vpa.hideVideoControls(); - vpa.videoControlsShowing = false; - } - }; - - public void start() { - this.postDelayed(hideVideoControls, DELAY); - } - - void stop() { - this.removeCallbacks(hideVideoControls); - } - - } - - //Hardware keyboard support @Override public boolean onKeyUp(int keyCode, KeyEvent event) {