From f44883e79fbb3d20e45902d3cfd4c4875f86f165 Mon Sep 17 00:00:00 2001 From: k1rakishou Date: Fri, 4 Oct 2019 21:47:01 +0300 Subject: [PATCH] Show video thumbnail on the lock screen --- .../newpipe/player/BackgroundPlayer.java | 61 ++++++++++++++----- .../player/helper/MediaSessionManager.java | 43 +++++++++++-- .../org/schabi/newpipe/util/BitmapUtils.java | 42 +++++++++++++ 3 files changed, 125 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java 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 90af3c29f..6486f4b03 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -25,6 +25,7 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.graphics.Bitmap; import android.os.Build; import android.os.IBinder; @@ -48,6 +49,7 @@ import org.schabi.newpipe.player.helper.LockManager; import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.resolver.AudioPlaybackResolver; import org.schabi.newpipe.player.resolver.MediaSourceTag; +import org.schabi.newpipe.util.BitmapUtils; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.ThemeHelper; @@ -193,18 +195,37 @@ public final class BackgroundPlayer extends Service { setupNotification(notRemoteView); setupNotification(bigNotRemoteView); - NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.notification_channel_id)) - .setOngoing(true) - .setSmallIcon(R.drawable.ic_newpipe_triangle_white) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - .setCustomContentView(notRemoteView) - .setCustomBigContentView(bigNotRemoteView); + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.notification_channel_id)); + builder.setOngoing(true); + builder.setSmallIcon(R.drawable.ic_newpipe_triangle_white); + builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); + builder.setCustomContentView(notRemoteView); + builder.setCustomBigContentView(bigNotRemoteView); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + basePlayerImpl.mediaSessionManager.setLockScreenArt( + builder, + getCenteredThumbnailBitmap() + ); + } + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { builder.setPriority(NotificationCompat.PRIORITY_MAX); } return builder; } + @Nullable + private Bitmap getCenteredThumbnailBitmap() { + int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; + int screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; + + return BitmapUtils.centerCrop( + basePlayerImpl.getThumbnail(), + screenWidth, + screenHeight); + } + private void setupNotification(RemoteViews remoteViews) { if (basePlayerImpl == null) return; @@ -252,8 +273,10 @@ public final class BackgroundPlayer extends Service { //if (DEBUG) Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]"); if (notBuilder == null) return; if (drawableId != -1) { - if (notRemoteView != null) notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId); - if (bigNotRemoteView != null) bigNotRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId); + if (notRemoteView != null) + notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId); + if (bigNotRemoteView != null) + bigNotRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId); } notificationManager.notify(NOTIFICATION_ID, notBuilder.build()); timesNotificationUpdated++; @@ -280,7 +303,8 @@ public final class BackgroundPlayer extends Service { protected class BasePlayerImpl extends BasePlayer { - @NonNull final private AudioPlaybackResolver resolver; + @NonNull + final private AudioPlaybackResolver resolver; private int cachedDuration; private String cachedDurationString; @@ -299,8 +323,10 @@ public final class BackgroundPlayer extends Service { super.handleIntent(intent); resetNotification(); - if (bigNotRemoteView != null) bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false); - if (notRemoteView != null) notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false); + if (bigNotRemoteView != null) + bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false); + if (notRemoteView != null) + notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false); startForeground(NOTIFICATION_ID, notBuilder.build()); } @@ -335,6 +361,7 @@ public final class BackgroundPlayer extends Service { updateNotificationThumbnail(); updateNotification(-1); } + /*////////////////////////////////////////////////////////////////////////// // States Implementation //////////////////////////////////////////////////////////////////////////*/ @@ -358,10 +385,12 @@ public final class BackgroundPlayer extends Service { if (!shouldUpdateOnProgress) return; if (timesNotificationUpdated > NOTIFICATION_UPDATES_BEFORE_RESET) { resetNotification(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /*Oreo*/) updateNotificationThumbnail(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /*Oreo*/) + updateNotificationThumbnail(); } + if (bigNotRemoteView != null) { - if(cachedDuration != duration) { + if (cachedDuration != duration) { cachedDuration = duration; cachedDurationString = getTimeString(duration); } @@ -389,8 +418,10 @@ public final class BackgroundPlayer extends Service { @Override public void destroy() { super.destroy(); - if (notRemoteView != null) notRemoteView.setImageViewBitmap(R.id.notificationCover, null); - if (bigNotRemoteView != null) bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, null); + if (notRemoteView != null) + notRemoteView.setImageViewBitmap(R.id.notificationCover, null); + if (bigNotRemoteView != null) + bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, null); } /*////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java index a5c703837..ec53e72fe 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java @@ -2,12 +2,18 @@ package org.schabi.newpipe.player.helper; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; +import android.media.MediaMetadata; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; +import android.support.v4.app.NotificationCompat; +import android.support.v4.media.MediaMetadataCompat; +import android.support.v4.media.session.MediaButtonReceiver; import android.support.v4.media.session.MediaSessionCompat; import android.view.KeyEvent; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.media.session.MediaButtonReceiver; +import android.support.v4.media.app.NotificationCompat.MediaStyle; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; @@ -40,13 +46,38 @@ public class MediaSessionManager { return MediaButtonReceiver.handleIntent(mediaSession, intent); } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public void setLockScreenArt( + NotificationCompat.Builder builder, + @Nullable Bitmap thumbnailBitmap + ) { + if (thumbnailBitmap == null) { + return; + } + + if (!mediaSession.isActive()) { + return; + } + + mediaSession.setMetadata( + new MediaMetadataCompat.Builder() + .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, thumbnailBitmap) + .build() + ); + + MediaStyle mediaStyle = new MediaStyle() + .setMediaSession(mediaSession.getSessionToken()); + + builder.setStyle(mediaStyle); + } + /** * Should be called on player destruction to prevent leakage. - * */ + */ public void dispose() { this.sessionConnector.setPlayer(null); this.sessionConnector.setQueueNavigator(null); this.mediaSession.setActive(false); this.mediaSession.release(); - } + } } diff --git a/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java b/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java new file mode 100644 index 000000000..2dac94912 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java @@ -0,0 +1,42 @@ +package org.schabi.newpipe.util; + +import android.graphics.Bitmap; +import android.support.annotation.Nullable; + +public class BitmapUtils { + + @Nullable + public static Bitmap centerCrop(Bitmap inputBitmap, int newWidth, int newHeight) { + if (inputBitmap == null || inputBitmap.isRecycled()) { + return null; + } + + float sourceWidth = inputBitmap.getWidth(); + float sourceHeight = inputBitmap.getHeight(); + + float xScale = newWidth / sourceWidth; + float yScale = newHeight / sourceHeight; + + float newXScale; + float newYScale; + + if (yScale > xScale) { + newXScale = (1.0f / yScale) * xScale; + newYScale = 1.0f; + } else { + newXScale = 1.0f; + newYScale = (1.0f / xScale) * yScale; + } + + float scaledWidth = newXScale * sourceWidth; + float scaledHeight = newYScale * sourceHeight; + + int left = (int) ((sourceWidth - scaledWidth) / 2); + int top = (int) ((sourceHeight - scaledHeight) / 2); + int width = (int) scaledWidth; + int height = (int) scaledHeight; + + return Bitmap.createBitmap(inputBitmap, left, top, width, height); + } + +}