Merge pull request #8899 from Stypox/fix-player-thumbnail-handling
Fix wrong thumbnail in notification on Android 13
This commit is contained in:
commit
ca29f6cc1f
|
@ -765,17 +765,15 @@ public final class Player implements PlaybackListener, Listener {
|
||||||
+ " -> " + bitmap.getWidth() + "x" + bitmap.getHeight() + "], from = ["
|
+ " -> " + bitmap.getWidth() + "x" + bitmap.getHeight() + "], from = ["
|
||||||
+ from + "]");
|
+ from + "]");
|
||||||
}
|
}
|
||||||
currentThumbnail = bitmap;
|
|
||||||
// there is a new thumbnail, so e.g. the end screen thumbnail needs to change, too.
|
// there is a new thumbnail, so e.g. the end screen thumbnail needs to change, too.
|
||||||
UIs.call(playerUi -> playerUi.onThumbnailLoaded(bitmap));
|
onThumbnailLoaded(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBitmapFailed(final Exception e, final Drawable errorDrawable) {
|
public void onBitmapFailed(final Exception e, final Drawable errorDrawable) {
|
||||||
Log.e(TAG, "Thumbnail - onBitmapFailed() called", e);
|
Log.e(TAG, "Thumbnail - onBitmapFailed() called", e);
|
||||||
currentThumbnail = null;
|
|
||||||
// there is a new thumbnail, so e.g. the end screen thumbnail needs to change, too.
|
// there is a new thumbnail, so e.g. the end screen thumbnail needs to change, too.
|
||||||
UIs.call(playerUi -> playerUi.onThumbnailLoaded(null));
|
onThumbnailLoaded(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -798,7 +796,7 @@ public final class Player implements PlaybackListener, Listener {
|
||||||
|
|
||||||
// Unset currentThumbnail, since it is now outdated. This ensures it is not used in media
|
// Unset currentThumbnail, since it is now outdated. This ensures it is not used in media
|
||||||
// session metadata while the new thumbnail is being loaded by Picasso.
|
// session metadata while the new thumbnail is being loaded by Picasso.
|
||||||
currentThumbnail = null;
|
onThumbnailLoaded(null);
|
||||||
if (isNullOrEmpty(url)) {
|
if (isNullOrEmpty(url)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -813,6 +811,16 @@ public final class Player implements PlaybackListener, Listener {
|
||||||
// cancel the Picasso job associated with the player thumbnail, if any
|
// cancel the Picasso job associated with the player thumbnail, if any
|
||||||
PicassoHelper.cancelTag(PICASSO_PLAYER_THUMBNAIL_TAG);
|
PicassoHelper.cancelTag(PICASSO_PLAYER_THUMBNAIL_TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onThumbnailLoaded(@Nullable final Bitmap bitmap) {
|
||||||
|
// Avoid useless thumbnail updates, if the thumbnail has not actually changed. Based on the
|
||||||
|
// thumbnail loading code, this if would be skipped only when both bitmaps are `null`, since
|
||||||
|
// onThumbnailLoaded won't be called twice with the same nonnull bitmap by Picasso's target.
|
||||||
|
if (currentThumbnail != bitmap) {
|
||||||
|
currentThumbnail = bitmap;
|
||||||
|
UIs.call(playerUi -> playerUi.onThumbnailLoaded(bitmap));
|
||||||
|
}
|
||||||
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
@ -1501,48 +1509,50 @@ public final class Player implements PlaybackListener, Listener {
|
||||||
Log.d(TAG, "Playback - onPlaybackSynchronize(was blocked: " + wasBlocked
|
Log.d(TAG, "Playback - onPlaybackSynchronize(was blocked: " + wasBlocked
|
||||||
+ ") called with item=[" + item.getTitle() + "], url=[" + item.getUrl() + "]");
|
+ ") called with item=[" + item.getTitle() + "], url=[" + item.getUrl() + "]");
|
||||||
}
|
}
|
||||||
if (exoPlayerIsNull() || playQueue == null) {
|
if (exoPlayerIsNull() || playQueue == null || currentItem == item) {
|
||||||
return;
|
return; // nothing to synchronize
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean hasPlayQueueItemChanged = currentItem != item;
|
final int playQueueIndex = playQueue.indexOf(item);
|
||||||
|
final int playlistIndex = simpleExoPlayer.getCurrentMediaItemIndex();
|
||||||
|
final int playlistSize = simpleExoPlayer.getCurrentTimeline().getWindowCount();
|
||||||
|
final boolean removeThumbnailBeforeSync = currentItem == null
|
||||||
|
|| currentItem.getServiceId() != item.getServiceId()
|
||||||
|
|| !currentItem.getUrl().equals(item.getUrl());
|
||||||
|
|
||||||
final int currentPlayQueueIndex = playQueue.indexOf(item);
|
|
||||||
final int currentPlaylistIndex = simpleExoPlayer.getCurrentMediaItemIndex();
|
|
||||||
final int currentPlaylistSize = simpleExoPlayer.getCurrentTimeline().getWindowCount();
|
|
||||||
|
|
||||||
// If nothing to synchronize
|
|
||||||
if (!hasPlayQueueItemChanged) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
currentItem = item;
|
currentItem = item;
|
||||||
|
|
||||||
// Check if on wrong window
|
if (playQueueIndex != playQueue.getIndex()) {
|
||||||
if (currentPlayQueueIndex != playQueue.getIndex()) {
|
// wrong window (this should be impossible, as this method is called with
|
||||||
Log.e(TAG, "Playback - Play Queue may be desynchronized: item "
|
// `item=playQueue.getItem()`, so the index of that item must be equal to `getIndex()`)
|
||||||
+ "index=[" + currentPlayQueueIndex + "], "
|
Log.e(TAG, "Playback - Play Queue may be not in sync: item index=["
|
||||||
+ "queue index=[" + playQueue.getIndex() + "]");
|
+ playQueueIndex + "], " + "queue index=[" + playQueue.getIndex() + "]");
|
||||||
|
|
||||||
// Check if bad seek position
|
} else if ((playlistSize > 0 && playQueueIndex >= playlistSize) || playQueueIndex < 0) {
|
||||||
} else if ((currentPlaylistSize > 0 && currentPlayQueueIndex >= currentPlaylistSize)
|
// the queue and the player's timeline are not in sync, since the play queue index
|
||||||
|| currentPlayQueueIndex < 0) {
|
// points outside of the timeline
|
||||||
Log.e(TAG, "Playback - Trying to seek to invalid "
|
Log.e(TAG, "Playback - Trying to seek to invalid index=[" + playQueueIndex
|
||||||
+ "index=[" + currentPlayQueueIndex + "] with "
|
+ "] with playlist length=[" + playlistSize + "]");
|
||||||
+ "playlist length=[" + currentPlaylistSize + "]");
|
|
||||||
|
|
||||||
} else if (wasBlocked || currentPlaylistIndex != currentPlayQueueIndex || !isPlaying()) {
|
} else if (wasBlocked || playlistIndex != playQueueIndex || !isPlaying()) {
|
||||||
|
// either the player needs to be unblocked, or the play queue index has just been
|
||||||
|
// changed and needs to be synchronized, or the player is not playing
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Playback - Rewinding to correct "
|
Log.d(TAG, "Playback - Rewinding to correct index=[" + playQueueIndex + "], "
|
||||||
+ "index=[" + currentPlayQueueIndex + "], "
|
+ "from=[" + playlistIndex + "], size=[" + playlistSize + "].");
|
||||||
+ "from=[" + currentPlaylistIndex + "], "
|
|
||||||
+ "size=[" + currentPlaylistSize + "].");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (removeThumbnailBeforeSync) {
|
||||||
|
// unset the current (now outdated) thumbnail to ensure it is not used during sync
|
||||||
|
onThumbnailLoaded(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync the player index with the queue index, and seek to the correct position
|
||||||
if (item.getRecoveryPosition() != PlayQueueItem.RECOVERY_UNSET) {
|
if (item.getRecoveryPosition() != PlayQueueItem.RECOVERY_UNSET) {
|
||||||
simpleExoPlayer.seekTo(currentPlayQueueIndex, item.getRecoveryPosition());
|
simpleExoPlayer.seekTo(playQueueIndex, item.getRecoveryPosition());
|
||||||
playQueue.unsetRecovery(currentPlayQueueIndex);
|
playQueue.unsetRecovery(playQueueIndex);
|
||||||
} else {
|
} else {
|
||||||
simpleExoPlayer.seekToDefaultPosition(currentPlayQueueIndex);
|
simpleExoPlayer.seekToDefaultPosition(playQueueIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ public final class NotificationPlayerUi extends PlayerUi {
|
||||||
@Override
|
@Override
|
||||||
public void onThumbnailLoaded(@Nullable final Bitmap bitmap) {
|
public void onThumbnailLoaded(@Nullable final Bitmap bitmap) {
|
||||||
super.onThumbnailLoaded(bitmap);
|
super.onThumbnailLoaded(bitmap);
|
||||||
notificationUtil.createNotificationIfNeededAndUpdate(false);
|
notificationUtil.updateThumbnail();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,6 +24,8 @@ import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
||||||
import static androidx.media.app.NotificationCompat.MediaStyle;
|
import static androidx.media.app.NotificationCompat.MediaStyle;
|
||||||
|
@ -40,8 +42,6 @@ import static org.schabi.newpipe.player.notification.NotificationConstants.ACTIO
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a utility class for player notifications.
|
* This is a utility class for player notifications.
|
||||||
*
|
|
||||||
* @author cool-student
|
|
||||||
*/
|
*/
|
||||||
public final class NotificationUtil {
|
public final class NotificationUtil {
|
||||||
private static final String TAG = NotificationUtil.class.getSimpleName();
|
private static final String TAG = NotificationUtil.class.getSimpleName();
|
||||||
|
@ -79,6 +79,19 @@ public final class NotificationUtil {
|
||||||
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void updateThumbnail() {
|
||||||
|
if (notificationBuilder != null) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "updateThumbnail() called with thumbnail = [" + Integer.toHexString(
|
||||||
|
Optional.ofNullable(player.getThumbnail()).map(Objects::hashCode).orElse(0))
|
||||||
|
+ "], title = [" + player.getVideoTitle() + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
setLargeIcon(notificationBuilder);
|
||||||
|
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private synchronized NotificationCompat.Builder createNotification() {
|
private synchronized NotificationCompat.Builder createNotification() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "createNotification()");
|
Log.d(TAG, "createNotification()");
|
||||||
|
@ -123,6 +136,9 @@ public final class NotificationUtil {
|
||||||
.setDeleteIntent(PendingIntent.getBroadcast(player.getContext(), NOTIFICATION_ID,
|
.setDeleteIntent(PendingIntent.getBroadcast(player.getContext(), NOTIFICATION_ID,
|
||||||
new Intent(ACTION_CLOSE), FLAG_UPDATE_CURRENT));
|
new Intent(ACTION_CLOSE), FLAG_UPDATE_CURRENT));
|
||||||
|
|
||||||
|
// set the initial value for the video thumbnail, updatable with updateNotificationThumbnail
|
||||||
|
setLargeIcon(builder);
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +158,6 @@ public final class NotificationUtil {
|
||||||
notificationBuilder.setTicker(player.getVideoTitle());
|
notificationBuilder.setTicker(player.getVideoTitle());
|
||||||
|
|
||||||
updateActions(notificationBuilder);
|
updateActions(notificationBuilder);
|
||||||
setLargeIcon(notificationBuilder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,6 @@ public abstract class VideoPlayerUi extends PlayerUi
|
||||||
private final Handler controlsVisibilityHandler = new Handler(Looper.getMainLooper());
|
private final Handler controlsVisibilityHandler = new Handler(Looper.getMainLooper());
|
||||||
@Nullable private SurfaceHolderCallback surfaceHolderCallback;
|
@Nullable private SurfaceHolderCallback surfaceHolderCallback;
|
||||||
boolean surfaceIsSetup = false;
|
boolean surfaceIsSetup = false;
|
||||||
@Nullable private Bitmap thumbnail = null;
|
|
||||||
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -385,9 +384,7 @@ public abstract class VideoPlayerUi extends PlayerUi
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
super.destroy();
|
super.destroy();
|
||||||
if (binding != null) {
|
binding.endScreen.setImageDrawable(null);
|
||||||
binding.endScreen.setImageBitmap(null);
|
|
||||||
}
|
|
||||||
deinitPlayerSeekOverlay();
|
deinitPlayerSeekOverlay();
|
||||||
deinitListeners();
|
deinitListeners();
|
||||||
}
|
}
|
||||||
|
@ -422,12 +419,10 @@ public abstract class VideoPlayerUi extends PlayerUi
|
||||||
public void onBroadcastReceived(final Intent intent) {
|
public void onBroadcastReceived(final Intent intent) {
|
||||||
super.onBroadcastReceived(intent);
|
super.onBroadcastReceived(intent);
|
||||||
if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
|
if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
|
||||||
// When the orientation changed, the screen height might be smaller.
|
// When the orientation changes, the screen height might be smaller. If the end screen
|
||||||
// If the end screen thumbnail is not re-scaled,
|
// thumbnail is not re-scaled, it can be larger than the current screen height and thus
|
||||||
// it can be larger than the current screen height
|
// enlarging the whole player. This causes the seekbar to be out of the visible area.
|
||||||
// and thus enlarging the whole player.
|
updateEndScreenThumbnail(player.getThumbnail());
|
||||||
// This causes the seekbar to be ouf the visible area.
|
|
||||||
updateEndScreenThumbnail();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
@ -449,11 +444,10 @@ public abstract class VideoPlayerUi extends PlayerUi
|
||||||
@Override
|
@Override
|
||||||
public void onThumbnailLoaded(@Nullable final Bitmap bitmap) {
|
public void onThumbnailLoaded(@Nullable final Bitmap bitmap) {
|
||||||
super.onThumbnailLoaded(bitmap);
|
super.onThumbnailLoaded(bitmap);
|
||||||
thumbnail = bitmap;
|
updateEndScreenThumbnail(bitmap);
|
||||||
updateEndScreenThumbnail();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateEndScreenThumbnail() {
|
private void updateEndScreenThumbnail(@Nullable final Bitmap thumbnail) {
|
||||||
if (thumbnail == null) {
|
if (thumbnail == null) {
|
||||||
// remove end screen thumbnail
|
// remove end screen thumbnail
|
||||||
binding.endScreen.setImageDrawable(null);
|
binding.endScreen.setImageDrawable(null);
|
||||||
|
|
Loading…
Reference in New Issue