mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-11-04 01:03:00 +00:00 
			
		
		
		
	Merge pull request #8899 from Stypox/fix-player-thumbnail-handling
Fix wrong thumbnail in notification on Android 13
This commit is contained in:
		@@ -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);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user