1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-12-23 16:40:32 +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:
Stypox 2022-09-19 08:49:39 +02:00 committed by GitHub
commit ca29f6cc1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 52 deletions

View File

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

View File

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

View File

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

View File

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