From 52f82ed2280918ec5c4c3d5c09a9f6fc6d5e6bec Mon Sep 17 00:00:00 2001 From: k1rakishou Date: Fri, 4 Oct 2019 21:47:01 +0300 Subject: [PATCH 01/10] Show video thumbnail on the lock screen --- .../newpipe/player/BackgroundPlayer.java | 60 ++++++++++++++----- .../player/helper/MediaSessionManager.java | 43 +++++++++++-- .../org/schabi/newpipe/util/BitmapUtils.java | 42 +++++++++++++ 3 files changed, 124 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 ab07ded22..4bcd719c2 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; @@ -189,18 +191,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; @@ -248,8 +269,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()); } @@ -275,7 +298,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; @@ -294,8 +318,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()); } @@ -330,6 +356,7 @@ public final class BackgroundPlayer extends Service { updateNotificationThumbnail(); updateNotification(-1); } + /*////////////////////////////////////////////////////////////////////////// // States Implementation //////////////////////////////////////////////////////////////////////////*/ @@ -352,9 +379,10 @@ public final class BackgroundPlayer extends Service { if (!shouldUpdateOnProgress) return; 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); } @@ -382,8 +410,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); + } + +} From cf13f5ca56950944f5ab44e8c00c8c7566e55ed2 Mon Sep 17 00:00:00 2001 From: k1rakishou Date: Fri, 8 Nov 2019 20:47:42 +0300 Subject: [PATCH 02/10] Rebase onto the latest dev, update appcompat dependencies to use androidx --- .../player/helper/MediaSessionManager.java | 21 +++++++++++-------- .../org/schabi/newpipe/util/BitmapUtils.java | 3 ++- 2 files changed, 14 insertions(+), 10 deletions(-) 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 ec53e72fe..b75ddb706 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 @@ -5,15 +5,16 @@ 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 android.support.v4.media.app.NotificationCompat.MediaStyle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.core.app.NotificationCompat; +import androidx.media.session.MediaButtonReceiver; +import androidx.media.app.NotificationCompat.MediaStyle; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; @@ -25,8 +26,10 @@ import org.schabi.newpipe.player.mediasession.PlayQueuePlaybackController; public class MediaSessionManager { private static final String TAG = "MediaSessionManager"; - @NonNull private final MediaSessionCompat mediaSession; - @NonNull private final MediaSessionConnector sessionConnector; + @NonNull + private final MediaSessionCompat mediaSession; + @NonNull + private final MediaSessionConnector sessionConnector; public MediaSessionManager(@NonNull final Context context, @NonNull final Player player, @@ -72,7 +75,7 @@ public class MediaSessionManager { } /** - * Should be called on player destruction to prevent leakage. + * Should be called on player destruction to prevent leakage.BitmapUtils */ public void dispose() { this.sessionConnector.setPlayer(null); diff --git a/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java b/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java index 2dac94912..a0e7de4ac 100644 --- a/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java +++ b/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java @@ -1,7 +1,8 @@ package org.schabi.newpipe.util; import android.graphics.Bitmap; -import android.support.annotation.Nullable; + +import androidx.annotation.Nullable; public class BitmapUtils { From e8437052d8565ab7c524c96186a69528a30f5a1c Mon Sep 17 00:00:00 2001 From: k1rakishou Date: Thu, 28 Nov 2019 21:46:37 +0300 Subject: [PATCH 03/10] Add a setting for the lock screen thumbnail feature --- .../newpipe/player/BackgroundPlayer.java | 28 ++++++++++++++++--- .../player/helper/MediaSessionManager.java | 14 ++++++++++ app/src/main/res/values/settings_keys.xml | 1 + app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/video_audio_settings.xml | 7 +++++ 5 files changed, 48 insertions(+), 4 deletions(-) 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 4bcd719c2..521daf184 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -25,13 +25,17 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.res.Resources; import android.graphics.Bitmap; import android.os.Build; import android.os.IBinder; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; + +import android.preference.PreferenceManager; import android.util.Log; import android.view.View; import android.widget.RemoteViews; @@ -77,6 +81,7 @@ public final class BackgroundPlayer extends Service { private BasePlayerImpl basePlayerImpl; private LockManager lockManager; + private SharedPreferences sharedPreferences; /*////////////////////////////////////////////////////////////////////////// // Service-Activity Binder @@ -106,6 +111,7 @@ public final class BackgroundPlayer extends Service { if (DEBUG) Log.d(TAG, "onCreate() called"); notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)); lockManager = new LockManager(this); + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); ThemeHelper.setTheme(this); basePlayerImpl = new BasePlayerImpl(this); @@ -199,10 +205,7 @@ public final class BackgroundPlayer extends Service { builder.setCustomBigContentView(bigNotRemoteView); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - basePlayerImpl.mediaSessionManager.setLockScreenArt( - builder, - getCenteredThumbnailBitmap() - ); + setLockScreenThumbnail(builder); } if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { @@ -211,6 +214,23 @@ public final class BackgroundPlayer extends Service { return builder; } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private void setLockScreenThumbnail(NotificationCompat.Builder builder) { + boolean isLockScreenThumbnailEnabled = sharedPreferences.getBoolean( + getString(R.string.enable_lock_screen_video_thumbnail_key), + true + ); + + if (isLockScreenThumbnailEnabled) { + basePlayerImpl.mediaSessionManager.setLockScreenArt( + builder, + getCenteredThumbnailBitmap() + ); + } else { + basePlayerImpl.mediaSessionManager.clearLockScreenArt(builder); + } + } + @Nullable private Bitmap getCenteredThumbnailBitmap() { int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; 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 b75ddb706..64022e39c 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 @@ -74,6 +74,20 @@ public class MediaSessionManager { builder.setStyle(mediaStyle); } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public void clearLockScreenArt(NotificationCompat.Builder builder) { + mediaSession.setMetadata( + new MediaMetadataCompat.Builder() + .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, null) + .build() + ); + + MediaStyle mediaStyle = new MediaStyle() + .setMediaSession(mediaSession.getSessionToken()); + + builder.setStyle(mediaStyle); + } + /** * Should be called on player destruction to prevent leakage.BitmapUtils */ diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 80f2bb1f4..109010b4e 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -152,6 +152,7 @@ main_page_content enable_playback_resume enable_playback_state_lists + enable_lock_screen_video_thumbnail import_data export_data diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a34b00ea9..16cf110a2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,7 +58,9 @@ Kore app not found. Install it? org.xbmc.kore Show \"Play with Kodi\" option + Enable lock screen video thumbnail Display an option to play a video via Kodi media center + When using the background player a video thumbnail will be displayed on the lock screen Audio Default audio format Default video format diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml index 4e1b1f8b2..a814fe0a9 100644 --- a/app/src/main/res/xml/video_audio_settings.xml +++ b/app/src/main/res/xml/video_audio_settings.xml @@ -81,6 +81,13 @@ android:summary="@string/show_play_with_kodi_summary" android:title="@string/show_play_with_kodi_title"/> + + Date: Fri, 4 Oct 2019 21:47:01 +0300 Subject: [PATCH 04/10] 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); + } + +} From 96de70b71e62cb70339a6185e6b53f4a31f8f5d3 Mon Sep 17 00:00:00 2001 From: k1rakishou Date: Fri, 8 Nov 2019 20:47:42 +0300 Subject: [PATCH 05/10] Rebase onto the latest dev, update appcompat dependencies to use androidx --- .../player/helper/MediaSessionManager.java | 21 +++++++++++-------- .../org/schabi/newpipe/util/BitmapUtils.java | 3 ++- 2 files changed, 14 insertions(+), 10 deletions(-) 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 ec53e72fe..b75ddb706 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 @@ -5,15 +5,16 @@ 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 android.support.v4.media.app.NotificationCompat.MediaStyle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.core.app.NotificationCompat; +import androidx.media.session.MediaButtonReceiver; +import androidx.media.app.NotificationCompat.MediaStyle; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; @@ -25,8 +26,10 @@ import org.schabi.newpipe.player.mediasession.PlayQueuePlaybackController; public class MediaSessionManager { private static final String TAG = "MediaSessionManager"; - @NonNull private final MediaSessionCompat mediaSession; - @NonNull private final MediaSessionConnector sessionConnector; + @NonNull + private final MediaSessionCompat mediaSession; + @NonNull + private final MediaSessionConnector sessionConnector; public MediaSessionManager(@NonNull final Context context, @NonNull final Player player, @@ -72,7 +75,7 @@ public class MediaSessionManager { } /** - * Should be called on player destruction to prevent leakage. + * Should be called on player destruction to prevent leakage.BitmapUtils */ public void dispose() { this.sessionConnector.setPlayer(null); diff --git a/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java b/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java index 2dac94912..a0e7de4ac 100644 --- a/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java +++ b/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java @@ -1,7 +1,8 @@ package org.schabi.newpipe.util; import android.graphics.Bitmap; -import android.support.annotation.Nullable; + +import androidx.annotation.Nullable; public class BitmapUtils { From 0395dc6e9e81e04aee8bb420383401832193054f Mon Sep 17 00:00:00 2001 From: k1rakishou Date: Thu, 28 Nov 2019 21:46:37 +0300 Subject: [PATCH 06/10] Add a setting for the lock screen thumbnail feature --- .../newpipe/player/BackgroundPlayer.java | 28 ++++++++++++++++--- .../player/helper/MediaSessionManager.java | 14 ++++++++++ app/src/main/res/values/settings_keys.xml | 1 + app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/video_audio_settings.xml | 7 +++++ 5 files changed, 48 insertions(+), 4 deletions(-) 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 6486f4b03..cbcd702f4 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -25,13 +25,17 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.res.Resources; import android.graphics.Bitmap; import android.os.Build; import android.os.IBinder; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; + +import android.preference.PreferenceManager; import android.util.Log; import android.view.View; import android.widget.RemoteViews; @@ -77,6 +81,7 @@ public final class BackgroundPlayer extends Service { private BasePlayerImpl basePlayerImpl; private LockManager lockManager; + private SharedPreferences sharedPreferences; /*////////////////////////////////////////////////////////////////////////// // Service-Activity Binder @@ -109,6 +114,7 @@ public final class BackgroundPlayer extends Service { if (DEBUG) Log.d(TAG, "onCreate() called"); notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)); lockManager = new LockManager(this); + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); ThemeHelper.setTheme(this); basePlayerImpl = new BasePlayerImpl(this); @@ -203,10 +209,7 @@ public final class BackgroundPlayer extends Service { builder.setCustomBigContentView(bigNotRemoteView); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - basePlayerImpl.mediaSessionManager.setLockScreenArt( - builder, - getCenteredThumbnailBitmap() - ); + setLockScreenThumbnail(builder); } if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { @@ -215,6 +218,23 @@ public final class BackgroundPlayer extends Service { return builder; } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private void setLockScreenThumbnail(NotificationCompat.Builder builder) { + boolean isLockScreenThumbnailEnabled = sharedPreferences.getBoolean( + getString(R.string.enable_lock_screen_video_thumbnail_key), + true + ); + + if (isLockScreenThumbnailEnabled) { + basePlayerImpl.mediaSessionManager.setLockScreenArt( + builder, + getCenteredThumbnailBitmap() + ); + } else { + basePlayerImpl.mediaSessionManager.clearLockScreenArt(builder); + } + } + @Nullable private Bitmap getCenteredThumbnailBitmap() { int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; 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 b75ddb706..64022e39c 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 @@ -74,6 +74,20 @@ public class MediaSessionManager { builder.setStyle(mediaStyle); } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public void clearLockScreenArt(NotificationCompat.Builder builder) { + mediaSession.setMetadata( + new MediaMetadataCompat.Builder() + .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, null) + .build() + ); + + MediaStyle mediaStyle = new MediaStyle() + .setMediaSession(mediaSession.getSessionToken()); + + builder.setStyle(mediaStyle); + } + /** * Should be called on player destruction to prevent leakage.BitmapUtils */ diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 6aaaa0630..4813833d1 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -175,6 +175,7 @@ main_page_content enable_playback_resume enable_playback_state_lists + enable_lock_screen_video_thumbnail import_data export_data diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6021df15e..a296e2db7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,7 +58,9 @@ Kore app not found. Install it? org.xbmc.kore Show \"Play with Kodi\" option + Enable lock screen video thumbnail Display an option to play a video via Kodi media center + When using the background player a video thumbnail will be displayed on the lock screen Audio Default audio format Default video format diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml index 0ff43ce90..ddf85811a 100644 --- a/app/src/main/res/xml/video_audio_settings.xml +++ b/app/src/main/res/xml/video_audio_settings.xml @@ -81,6 +81,13 @@ android:summary="@string/show_play_with_kodi_summary" android:title="@string/show_play_with_kodi_title"/> + + Date: Wed, 1 Jan 2020 17:18:58 +0100 Subject: [PATCH 07/10] Enable lockscreen video thumbnail by default --- .../org/schabi/newpipe/player/helper/MediaSessionManager.java | 2 +- app/src/main/res/xml/video_audio_settings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 64022e39c..51684f506 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 @@ -89,7 +89,7 @@ public class MediaSessionManager { } /** - * Should be called on player destruction to prevent leakage.BitmapUtils + * Should be called on player destruction to prevent leakage. */ public void dispose() { this.sessionConnector.setPlayer(null); diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml index ddf85811a..d1757919b 100644 --- a/app/src/main/res/xml/video_audio_settings.xml +++ b/app/src/main/res/xml/video_audio_settings.xml @@ -83,7 +83,7 @@ From 718acb505930e4a7d2dbd7b3840b73677f5512bb Mon Sep 17 00:00:00 2001 From: TobiGr Date: Thu, 2 Jan 2020 15:00:22 +0100 Subject: [PATCH 08/10] Code improvements --- .../newpipe/player/helper/MediaSessionManager.java | 11 ++--------- .../java/org/schabi/newpipe/util/BitmapUtils.java | 4 ++-- 2 files changed, 4 insertions(+), 11 deletions(-) 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 51684f506..8b9369613 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 @@ -50,15 +50,8 @@ public class MediaSessionManager { } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public void setLockScreenArt( - NotificationCompat.Builder builder, - @Nullable Bitmap thumbnailBitmap - ) { - if (thumbnailBitmap == null) { - return; - } - - if (!mediaSession.isActive()) { + public void setLockScreenArt(NotificationCompat.Builder builder, @Nullable Bitmap thumbnailBitmap) { + if (thumbnailBitmap == null || !mediaSession.isActive()) { return; } diff --git a/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java b/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java index a0e7de4ac..7ad71eb5c 100644 --- a/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java +++ b/app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java @@ -22,11 +22,11 @@ public class BitmapUtils { float newYScale; if (yScale > xScale) { - newXScale = (1.0f / yScale) * xScale; + newXScale = xScale / yScale; newYScale = 1.0f; } else { newXScale = 1.0f; - newYScale = (1.0f / xScale) * yScale; + newYScale = yScale / xScale; } float scaledWidth = newXScale * sourceWidth; From c46a0f7b2ebd9fbe73c3bc33c5b62ae64c529a23 Mon Sep 17 00:00:00 2001 From: k1rakishou Date: Fri, 3 Jan 2020 13:00:53 +0300 Subject: [PATCH 09/10] Code-review changes --- .../org/schabi/newpipe/player/BackgroundPlayer.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 f36e352a6..9e896b14f 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -201,12 +201,12 @@ public final class BackgroundPlayer extends Service { setupNotification(notRemoteView); setupNotification(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); + 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); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { setLockScreenThumbnail(builder); From eb5fb42da9776149db8c882cf16a4da4f8531c9f Mon Sep 17 00:00:00 2001 From: k1rakishou Date: Fri, 3 Jan 2020 16:29:04 +0300 Subject: [PATCH 10/10] Couple more code review changes --- .../org/schabi/newpipe/player/BackgroundPlayer.java | 10 +++++++--- .../newpipe/player/helper/MediaSessionManager.java | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) 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 9e896b14f..76da7da36 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -403,9 +403,13 @@ public final class BackgroundPlayer extends Service { updateProgress(currentProgress, duration, bufferPercent); if (!shouldUpdateOnProgress) return; - if (timesNotificationUpdated > NOTIFICATION_UPDATES_BEFORE_RESET) {resetNotification(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /*Oreo*/) - updateNotificationThumbnail();} + if (timesNotificationUpdated > NOTIFICATION_UPDATES_BEFORE_RESET) { + resetNotification(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /*Oreo*/) { + updateNotificationThumbnail(); + } + } if (bigNotRemoteView != null) { if (cachedDuration != duration) { cachedDuration = duration; 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 9134d6144..8b9369613 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 @@ -82,7 +82,7 @@ public class MediaSessionManager { } /** - * Should be called on player destruction to prevent leakage.BitmapUtils + * Should be called on player destruction to prevent leakage. */ public void dispose() { this.sessionConnector.setPlayer(null);