From 2d6317bd24d76d34f561600f25fd152f6bd2cc6d Mon Sep 17 00:00:00 2001 From: John Zhen Mo Date: Mon, 28 May 2018 19:51:41 -0700 Subject: [PATCH] -Fixed audio-only streams thumbnail not displaying on video players. -Fixed potential play queue desynchronization due to fast forwarding on silence. -Added current thumbnail storing in base player to allow immediate retrieval for notification building. -Removed video player buffer spinner during interim buffering but not initial buffering. -Reverted foreground notification stopping on pause and on complete. --- .../newpipe/player/BackgroundPlayer.java | 85 ++++--------------- .../org/schabi/newpipe/player/BasePlayer.java | 31 +++++-- .../newpipe/player/MainVideoPlayer.java | 1 - .../newpipe/player/PopupVideoPlayer.java | 52 ++++-------- .../schabi/newpipe/player/VideoPlayer.java | 7 +- 5 files changed, 64 insertions(+), 112 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java index 231163b7b..805326abd 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -188,7 +188,9 @@ public final class BackgroundPlayer extends Service { .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setCustomContentView(notRemoteView) .setCustomBigContentView(bigNotRemoteView); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) builder.setPriority(NotificationCompat.PRIORITY_MAX); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { + builder.setPriority(NotificationCompat.PRIORITY_MAX); + } return builder; } @@ -197,6 +199,7 @@ public final class BackgroundPlayer extends Service { remoteViews.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle()); remoteViews.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName()); + remoteViews.setImageViewBitmap(R.id.notificationCover, basePlayerImpl.getThumbnail()); remoteViews.setOnClickPendingIntent(R.id.notificationPlayPause, PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT)); @@ -244,6 +247,7 @@ public final class BackgroundPlayer extends Service { } notificationManager.notify(NOTIFICATION_ID, notBuilder.build()); } + /*////////////////////////////////////////////////////////////////////////// // Utils //////////////////////////////////////////////////////////////////////////*/ @@ -291,57 +295,26 @@ public final class BackgroundPlayer extends Service { // Thumbnail Loading //////////////////////////////////////////////////////////////////////////*/ - private void setDummyRemoteViewThumbnail() { - resetNotification(); - if (notRemoteView != null) { - notRemoteView.setImageViewResource(R.id.notificationCover, - R.drawable.dummy_thumbnail); - } - if (bigNotRemoteView != null) { - bigNotRemoteView.setImageViewResource(R.id.notificationCover, - R.drawable.dummy_thumbnail); - } - updateNotification(-1); - } - - @Override - public void onLoadingStarted(String imageUri, View view) { - super.onLoadingStarted(imageUri, view); - setDummyRemoteViewThumbnail(); - } - @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { super.onLoadingComplete(imageUri, view, loadedImage); - if (loadedImage == null) { - setDummyRemoteViewThumbnail(); - return; - } - - // rebuild notification here since remote view does not release bitmaps, - // causing memory leaks resetNotification(); - if (notRemoteView != null) { - notRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage); - } - if (bigNotRemoteView != null) { - bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage); - } updateNotification(-1); } @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) { super.onLoadingFailed(imageUri, view, failReason); - setDummyRemoteViewThumbnail(); + resetNotification(); + updateNotification(-1); } @Override public void onLoadingCancelled(String imageUri, View view) { super.onLoadingCancelled(imageUri, view); - setDummyRemoteViewThumbnail(); + resetNotification(); + updateNotification(-1); } - /*////////////////////////////////////////////////////////////////////////// // States Implementation //////////////////////////////////////////////////////////////////////////*/ @@ -544,60 +517,38 @@ public final class BackgroundPlayer extends Service { @Override public void changeState(int state) { - resetNotification(); super.changeState(state); updatePlayback(); } - @Override - public void onBlocked() { - super.onBlocked(); - updateNotification(-1); - startForeground(NOTIFICATION_ID, notBuilder.build()); - } - - @Override - public void onBuffering() { - super.onBuffering(); - updateNotification(-1); - startForeground(NOTIFICATION_ID, notBuilder.build()); - } - - @Override - public void onPausedSeek() { - super.onPausedSeek(); - updateNotification(-1); - startForeground(NOTIFICATION_ID, notBuilder.build()); - } - @Override public void onPlaying() { super.onPlaying(); + resetNotification(); updateNotification(R.drawable.ic_pause_white); - lockManager.acquireWifiAndCpu(); - startForeground(NOTIFICATION_ID, notBuilder.build()); } @Override public void onPaused() { super.onPaused(); + resetNotification(); updateNotification(R.drawable.ic_play_arrow_white); - lockManager.releaseWifiAndCpu(); - stopForeground(false); } @Override public void onCompleted() { super.onCompleted(); - - if (bigNotRemoteView != null) bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 100, false); - if (notRemoteView != null) notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 100, false); + resetNotification(); + if (bigNotRemoteView != null) { + bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 100, false); + } + if (notRemoteView != null) { + notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 100, false); + } updateNotification(R.drawable.ic_replay_white); - lockManager.releaseWifiAndCpu(); - stopForeground(false); } } } diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index ad62c71c3..12e65cba1 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -24,6 +24,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.media.AudioManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -139,6 +140,7 @@ public abstract class BasePlayer implements @Nullable private PlayQueueItem currentItem; @Nullable private MediaSourceTag currentMetadata; + @Nullable private Bitmap currentThumbnail; @Nullable protected Toast errorToast; @@ -317,6 +319,7 @@ public abstract class BasePlayer implements public void onLoadingFailed(String imageUri, View view, FailReason failReason) { Log.e(TAG, "Thumbnail - onLoadingFailed() called on imageUri = [" + imageUri + "]", failReason.getCause()); + currentThumbnail = null; } @Override @@ -324,12 +327,14 @@ public abstract class BasePlayer implements if (DEBUG) Log.d(TAG, "Thumbnail - onLoadingComplete() called with: " + "imageUri = [" + imageUri + "], view = [" + view + "], " + "loadedImage = [" + loadedImage + "]"); + currentThumbnail = loadedImage; } @Override public void onLoadingCancelled(String imageUri, View view) { if (DEBUG) Log.d(TAG, "Thumbnail - onLoadingCancelled() called with: " + "imageUri = [" + imageUri + "], view = [" + view + "]"); + currentThumbnail = null; } /*////////////////////////////////////////////////////////////////////////// @@ -653,19 +658,25 @@ public abstract class BasePlayer implements public void onPositionDiscontinuity(@Player.DiscontinuityReason final int reason) { if (DEBUG) Log.d(TAG, "ExoPlayer - onPositionDiscontinuity() called with " + "reason = [" + reason + "]"); + if (playQueue == null) return; // Refresh the playback if there is a transition to the next video - final int newPeriodIndex = simpleExoPlayer.getCurrentPeriodIndex(); + final int newWindowIndex = simpleExoPlayer.getCurrentWindowIndex(); switch (reason) { case DISCONTINUITY_REASON_PERIOD_TRANSITION: - if (newPeriodIndex == playQueue.getIndex()) { + // When player is in single repeat mode and a period transition occurs, + // we need to register a view count here since no metadata has changed + if (getRepeatMode() == Player.REPEAT_MODE_ONE && + newWindowIndex == playQueue.getIndex()) { registerView(); - } else { - playQueue.setIndex(newPeriodIndex); + break; } case DISCONTINUITY_REASON_SEEK: case DISCONTINUITY_REASON_SEEK_ADJUSTMENT: case DISCONTINUITY_REASON_INTERNAL: + if (playQueue.getIndex() != newWindowIndex) { + playQueue.setIndex(newWindowIndex); + } break; } @@ -777,9 +788,10 @@ public abstract class BasePlayer implements } protected void onMetadataChanged(@NonNull final MediaSourceTag tag) { - Log.d(TAG, "Playback - onMetadataChanged() called, " + - "playing: " + tag.getMetadata().getName()); final StreamInfo info = tag.getMetadata(); + if (DEBUG) { + Log.d(TAG, "Playback - onMetadataChanged() called, playing: " + info.getName()); + } initThumbnail(info.getThumbnailUrl()); registerView(); @@ -1045,6 +1057,13 @@ public abstract class BasePlayer implements return currentItem == null ? context.getString(R.string.unknown_content) : currentItem.getUploader(); } + @Nullable + public Bitmap getThumbnail() { + return currentThumbnail == null ? + BitmapFactory.decodeResource(context.getResources(), R.drawable.dummy_thumbnail) : + currentThumbnail; + } + /** Checks if the current playback is a livestream AND is playing at or beyond the live edge */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") public boolean isLiveEdge() { diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index bf728f9d5..9f3b5d020 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -720,7 +720,6 @@ public final class MainVideoPlayer extends AppCompatActivity @Override public void onBuffering() { super.onBuffering(); - animatePlayButtons(false, 100); getRootView().setKeepScreenOn(true); } diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index e2929d26f..3bee984a8 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -34,7 +34,6 @@ import android.os.Build; import android.os.IBinder; import android.preference.PreferenceManager; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.util.DisplayMetrics; import android.util.Log; @@ -229,6 +228,7 @@ public final class PopupVideoPlayer extends Service { notRemoteView.setTextViewText(R.id.notificationSongName, playerImpl.getVideoTitle()); notRemoteView.setTextViewText(R.id.notificationArtist, playerImpl.getUploaderName()); + notRemoteView.setImageViewBitmap(R.id.notificationCover, playerImpl.getThumbnail()); notRemoteView.setOnClickPendingIntent(R.id.notificationPlayPause, PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT)); @@ -517,48 +517,27 @@ public final class PopupVideoPlayer extends Service { // Thumbnail Loading //////////////////////////////////////////////////////////////////////////*/ - private void setDummyRemoteViewThumbnail() { - resetNotification(); - if (notRemoteView != null) { - notRemoteView.setImageViewResource(R.id.notificationCover, - R.drawable.dummy_thumbnail); - } - updateNotification(-1); - } - - @Override - public void onLoadingStarted(String imageUri, View view) { - super.onLoadingStarted(imageUri, view); - setDummyRemoteViewThumbnail(); - } - @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { super.onLoadingComplete(imageUri, view, loadedImage); - if (loadedImage == null) { - setDummyRemoteViewThumbnail(); - return; - } - // rebuild notification here since remote view does not release bitmaps, // causing memory leaks resetNotification(); - if (notRemoteView != null) { - notRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage); - } updateNotification(-1); } @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) { super.onLoadingFailed(imageUri, view, failReason); - setDummyRemoteViewThumbnail(); + resetNotification(); + updateNotification(-1); } @Override public void onLoadingCancelled(String imageUri, View view) { super.onLoadingCancelled(imageUri, view); - setDummyRemoteViewThumbnail(); + resetNotification(); + updateNotification(-1); } /*////////////////////////////////////////////////////////////////////////// @@ -613,6 +592,7 @@ public final class PopupVideoPlayer extends Service { super.onRepeatModeChanged(i); setRepeatModeRemote(notRemoteView, i); updatePlayback(); + resetNotification(); updateNotification(-1); } @@ -683,7 +663,6 @@ public final class PopupVideoPlayer extends Service { @Override public void changeState(int state) { - resetNotification(); super.changeState(state); updatePlayback(); } @@ -691,14 +670,16 @@ public final class PopupVideoPlayer extends Service { @Override public void onBlocked() { super.onBlocked(); + resetNotification(); updateNotification(R.drawable.ic_play_arrow_white); - startForeground(NOTIFICATION_ID, notBuilder.build()); } @Override public void onPlaying() { super.onPlaying(); + resetNotification(); updateNotification(R.drawable.ic_pause_white); + videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white); hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); @@ -713,16 +694,17 @@ public final class PopupVideoPlayer extends Service { @Override public void onBuffering() { super.onBuffering(); + resetNotification(); updateNotification(R.drawable.ic_play_arrow_white); - startForeground(NOTIFICATION_ID, notBuilder.build()); } @Override public void onPaused() { super.onPaused(); + resetNotification(); updateNotification(R.drawable.ic_play_arrow_white); - videoPlayPause.setBackgroundResource(R.drawable.ic_play_arrow_white); + videoPlayPause.setBackgroundResource(R.drawable.ic_play_arrow_white); lockManager.releaseWifiAndCpu(); windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; @@ -734,17 +716,19 @@ public final class PopupVideoPlayer extends Service { @Override public void onPausedSeek() { super.onPausedSeek(); - videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white); + resetNotification(); updateNotification(R.drawable.ic_play_arrow_white); - startForeground(NOTIFICATION_ID, notBuilder.build()); + + videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white); } @Override public void onCompleted() { super.onCompleted(); + resetNotification(); updateNotification(R.drawable.ic_replay_white); - videoPlayPause.setBackgroundResource(R.drawable.ic_replay_white); + videoPlayPause.setBackgroundResource(R.drawable.ic_replay_white); lockManager.releaseWifiAndCpu(); windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; @@ -768,8 +752,6 @@ public final class PopupVideoPlayer extends Service { super.hideControlsAndButton(duration, delay, videoPlayPause); } - - /*////////////////////////////////////////////////////////////////////////// // Utils //////////////////////////////////////////////////////////////////////////*/ diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index 1ca0ff4ee..73f5e94b1 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -333,16 +333,19 @@ public abstract class VideoPlayer extends BasePlayer switch (tag.getMetadata().getStreamType()) { case AUDIO_STREAM: surfaceView.setVisibility(View.GONE); + endScreen.setVisibility(View.VISIBLE); playbackEndTime.setVisibility(View.VISIBLE); break; case AUDIO_LIVE_STREAM: surfaceView.setVisibility(View.GONE); + endScreen.setVisibility(View.VISIBLE); playbackLiveSync.setVisibility(View.VISIBLE); break; case LIVE_STREAM: surfaceView.setVisibility(View.VISIBLE); + endScreen.setVisibility(View.GONE); playbackLiveSync.setVisibility(View.VISIBLE); break; @@ -357,6 +360,7 @@ public abstract class VideoPlayer extends BasePlayer qualityTextView.setVisibility(View.VISIBLE); surfaceView.setVisibility(View.VISIBLE); default: + endScreen.setVisibility(View.GONE); playbackEndTime.setVisibility(View.VISIBLE); break; } @@ -387,7 +391,6 @@ public abstract class VideoPlayer extends BasePlayer if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN); - animateView(endScreen, false, 0); loadingPanel.setBackgroundColor(Color.BLACK); animateView(loadingPanel, true, 0); animateView(surfaceForeground, true, 100); @@ -407,14 +410,12 @@ public abstract class VideoPlayer extends BasePlayer loadingPanel.setVisibility(View.GONE); animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200); - animateView(endScreen, false, 0); } @Override public void onBuffering() { if (DEBUG) Log.d(TAG, "onBuffering() called"); loadingPanel.setBackgroundColor(Color.TRANSPARENT); - animateView(loadingPanel, true, 500); } @Override