-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.
This commit is contained in:
John Zhen Mo 2018-05-28 19:51:41 -07:00
parent 157b064214
commit 2d6317bd24
5 changed files with 64 additions and 112 deletions

View File

@ -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);
}
}
}

View File

@ -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() {

View File

@ -720,7 +720,6 @@ public final class MainVideoPlayer extends AppCompatActivity
@Override
public void onBuffering() {
super.onBuffering();
animatePlayButtons(false, 100);
getRootView().setKeepScreenOn(true);
}

View File

@ -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
//////////////////////////////////////////////////////////////////////////*/

View File

@ -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