Show video thumbnail on the lock screen
This commit is contained in:
parent
eeeeeef3a7
commit
52f82ed228
3 changed files with 124 additions and 21 deletions
|
@ -25,6 +25,7 @@ import android.app.Service;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
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.playqueue.PlayQueueItem;
|
||||||
import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
|
import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
|
||||||
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
||||||
|
import org.schabi.newpipe.util.BitmapUtils;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
@ -189,18 +191,37 @@ public final class BackgroundPlayer extends Service {
|
||||||
setupNotification(notRemoteView);
|
setupNotification(notRemoteView);
|
||||||
setupNotification(bigNotRemoteView);
|
setupNotification(bigNotRemoteView);
|
||||||
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.notification_channel_id));
|
||||||
.setOngoing(true)
|
builder.setOngoing(true);
|
||||||
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
|
builder.setSmallIcon(R.drawable.ic_newpipe_triangle_white);
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
|
||||||
.setCustomContentView(notRemoteView)
|
builder.setCustomContentView(notRemoteView);
|
||||||
.setCustomBigContentView(bigNotRemoteView);
|
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) {
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
builder.setPriority(NotificationCompat.PRIORITY_MAX);
|
builder.setPriority(NotificationCompat.PRIORITY_MAX);
|
||||||
}
|
}
|
||||||
return builder;
|
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) {
|
private void setupNotification(RemoteViews remoteViews) {
|
||||||
if (basePlayerImpl == null) return;
|
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 (DEBUG) Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
|
||||||
if (notBuilder == null) return;
|
if (notBuilder == null) return;
|
||||||
if (drawableId != -1) {
|
if (drawableId != -1) {
|
||||||
if (notRemoteView != null) notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
if (notRemoteView != null)
|
||||||
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
||||||
|
if (bigNotRemoteView != null)
|
||||||
|
bigNotRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
||||||
}
|
}
|
||||||
notificationManager.notify(NOTIFICATION_ID, notBuilder.build());
|
notificationManager.notify(NOTIFICATION_ID, notBuilder.build());
|
||||||
}
|
}
|
||||||
|
@ -275,7 +298,8 @@ public final class BackgroundPlayer extends Service {
|
||||||
|
|
||||||
protected class BasePlayerImpl extends BasePlayer {
|
protected class BasePlayerImpl extends BasePlayer {
|
||||||
|
|
||||||
@NonNull final private AudioPlaybackResolver resolver;
|
@NonNull
|
||||||
|
final private AudioPlaybackResolver resolver;
|
||||||
private int cachedDuration;
|
private int cachedDuration;
|
||||||
private String cachedDurationString;
|
private String cachedDurationString;
|
||||||
|
|
||||||
|
@ -294,8 +318,10 @@ public final class BackgroundPlayer extends Service {
|
||||||
super.handleIntent(intent);
|
super.handleIntent(intent);
|
||||||
|
|
||||||
resetNotification();
|
resetNotification();
|
||||||
if (bigNotRemoteView != null) bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
if (bigNotRemoteView != null)
|
||||||
if (notRemoteView != null) notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
||||||
|
if (notRemoteView != null)
|
||||||
|
notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
||||||
startForeground(NOTIFICATION_ID, notBuilder.build());
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,6 +356,7 @@ public final class BackgroundPlayer extends Service {
|
||||||
updateNotificationThumbnail();
|
updateNotificationThumbnail();
|
||||||
updateNotification(-1);
|
updateNotification(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// States Implementation
|
// States Implementation
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -352,7 +379,8 @@ public final class BackgroundPlayer extends Service {
|
||||||
|
|
||||||
if (!shouldUpdateOnProgress) return;
|
if (!shouldUpdateOnProgress) return;
|
||||||
resetNotification();
|
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 (bigNotRemoteView != null) {
|
||||||
if (cachedDuration != duration) {
|
if (cachedDuration != duration) {
|
||||||
cachedDuration = duration;
|
cachedDuration = duration;
|
||||||
|
@ -382,8 +410,10 @@ public final class BackgroundPlayer extends Service {
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
super.destroy();
|
super.destroy();
|
||||||
if (notRemoteView != null) notRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
if (notRemoteView != null)
|
||||||
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
notRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
||||||
|
if (bigNotRemoteView != null)
|
||||||
|
bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -2,12 +2,18 @@ package org.schabi.newpipe.player.helper;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
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.support.v4.media.session.MediaSessionCompat;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
import android.support.v4.media.app.NotificationCompat.MediaStyle;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.media.session.MediaButtonReceiver;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
|
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
|
||||||
|
@ -40,9 +46,34 @@ public class MediaSessionManager {
|
||||||
return MediaButtonReceiver.handleIntent(mediaSession, intent);
|
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.
|
* Should be called on player destruction to prevent leakage.
|
||||||
* */
|
*/
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
this.sessionConnector.setPlayer(null);
|
this.sessionConnector.setPlayer(null);
|
||||||
this.sessionConnector.setQueueNavigator(null);
|
this.sessionConnector.setQueueNavigator(null);
|
||||||
|
|
42
app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java
Normal file
42
app/src/main/java/org/schabi/newpipe/util/BitmapUtils.java
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue