Notification Improvements
- add MediaStyle notifications for Background and Popup playback - reduce excessive notification updating ( / recreating of Notification.Builder object) when playing background / popup media - add new buffering state indicator (can be disabled) - upscale close icon / downscale replay icon - add notification slot settings - move notification settings to appearance - fix Metadata (song title, artist and album art) sometimes not being set correctly - other misc notification fixes Co-authored-by: wb9688 <wb9688@users.noreply.github.com>
@ -19,44 +19,33 @@
|
||||
|
||||
package org.schabi.newpipe.player;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
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 android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||
|
||||
import org.schabi.newpipe.BuildConfig;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.player.event.PlayerEventListener;
|
||||
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;
|
||||
|
||||
import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
|
||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||
|
||||
/**
|
||||
@ -65,6 +54,9 @@ import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||
* @author mauriciocolli
|
||||
*/
|
||||
public final class BackgroundPlayer extends Service {
|
||||
private static final String TAG = "BackgroundPlayer";
|
||||
private static final boolean DEBUG = BasePlayer.DEBUG;
|
||||
|
||||
public static final String ACTION_CLOSE
|
||||
= "org.schabi.newpipe.player.BackgroundPlayer.CLOSE";
|
||||
public static final String ACTION_PLAY_PAUSE
|
||||
@ -79,30 +71,27 @@ public final class BackgroundPlayer extends Service {
|
||||
= "org.schabi.newpipe.player.BackgroundPlayer.ACTION_FAST_REWIND";
|
||||
public static final String ACTION_FAST_FORWARD
|
||||
= "org.schabi.newpipe.player.BackgroundPlayer.ACTION_FAST_FORWARD";
|
||||
public static final String ACTION_BUFFERING
|
||||
= "org.schabi.newpipe.player.BackgroundPlayer.ACTION_BUFFERING";
|
||||
public static final String ACTION_SHUFFLE
|
||||
= "org.schabi.newpipe.player.BackgroundPlayer.ACTION_SHUFFLE";
|
||||
|
||||
public static final String SET_IMAGE_RESOURCE_METHOD = "setImageResource";
|
||||
private static final String TAG = "BackgroundPlayer";
|
||||
private static final boolean DEBUG = BasePlayer.DEBUG;
|
||||
private static final int NOTIFICATION_ID = 123789;
|
||||
private static final int NOTIFICATION_UPDATES_BEFORE_RESET = 60;
|
||||
|
||||
|
||||
private BasePlayerImpl basePlayerImpl;
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
private boolean shouldUpdateOnProgress; // only used for old notifications
|
||||
private boolean isForwardPressed;
|
||||
private boolean isRewindPressed;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Service-Activity Binder
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Notification
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
private PlayerEventListener activityListener;
|
||||
private IBinder mBinder;
|
||||
private NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder notBuilder;
|
||||
private RemoteViews notRemoteView;
|
||||
private RemoteViews bigNotRemoteView;
|
||||
private boolean shouldUpdateOnProgress;
|
||||
private int timesNotificationUpdated;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Service's LifeCycle
|
||||
@ -113,7 +102,7 @@ public final class BackgroundPlayer extends Service {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onCreate() called");
|
||||
}
|
||||
notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
|
||||
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
assureCorrectAppLanguage(this);
|
||||
ThemeHelper.setTheme(this);
|
||||
@ -127,7 +116,7 @@ public final class BackgroundPlayer extends Service {
|
||||
@Override
|
||||
public int onStartCommand(final Intent intent, final int flags, final int startId) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onStartCommand() called with: intent = [" + intent + "], "
|
||||
Log.d(TAG, "N_ onStartCommand() called with: intent = [" + intent + "], "
|
||||
+ "flags = [" + flags + "], startId = [" + startId + "]");
|
||||
}
|
||||
basePlayerImpl.handleIntent(intent);
|
||||
@ -160,7 +149,7 @@ public final class BackgroundPlayer extends Service {
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
private void onClose() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onClose() called");
|
||||
Log.d(TAG, "N_ onClose() called");
|
||||
}
|
||||
|
||||
if (basePlayerImpl != null) {
|
||||
@ -168,9 +157,8 @@ public final class BackgroundPlayer extends Service {
|
||||
basePlayerImpl.stopActivityBinding();
|
||||
basePlayerImpl.destroy();
|
||||
}
|
||||
if (notificationManager != null) {
|
||||
notificationManager.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
NotificationUtil.getInstance()
|
||||
.cancelNotification(NotificationUtil.NOTIFICATION_ID_BACKGROUND);
|
||||
mBinder = null;
|
||||
basePlayerImpl = null;
|
||||
|
||||
@ -191,168 +179,9 @@ public final class BackgroundPlayer extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Notification
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void resetNotification() {
|
||||
notBuilder = createNotification();
|
||||
timesNotificationUpdated = 0;
|
||||
}
|
||||
|
||||
private NotificationCompat.Builder createNotification() {
|
||||
notRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
|
||||
R.layout.player_background_notification);
|
||||
bigNotRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
|
||||
R.layout.player_background_notification_expanded);
|
||||
|
||||
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);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
setLockScreenThumbnail(builder);
|
||||
}
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
|
||||
builder.setPriority(NotificationCompat.PRIORITY_MAX);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
private void setLockScreenThumbnail(final 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() {
|
||||
final int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
|
||||
final int screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels;
|
||||
|
||||
return BitmapUtils.centerCrop(basePlayerImpl.getThumbnail(), screenWidth, screenHeight);
|
||||
}
|
||||
|
||||
private void setupNotification(final RemoteViews remoteViews) {
|
||||
if (basePlayerImpl == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
remoteViews.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
|
||||
remoteViews.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName());
|
||||
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationPlayPause,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
|
||||
new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationStop,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
|
||||
new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationRepeat,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
|
||||
new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
|
||||
// Starts background player activity -- attempts to unlock lockscreen
|
||||
final Intent intent = NavigationHelper.getBackgroundPlayerActivityIntent(this);
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationContent,
|
||||
PendingIntent.getActivity(this, NOTIFICATION_ID, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
|
||||
if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) {
|
||||
remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD,
|
||||
R.drawable.exo_controls_previous);
|
||||
remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD,
|
||||
R.drawable.exo_controls_next);
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
|
||||
new Intent(ACTION_PLAY_PREVIOUS), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
|
||||
new Intent(ACTION_PLAY_NEXT), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
} else {
|
||||
remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD,
|
||||
R.drawable.exo_controls_rewind);
|
||||
remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD,
|
||||
R.drawable.exo_controls_fastforward);
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
|
||||
new Intent(ACTION_FAST_REWIND), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID,
|
||||
new Intent(ACTION_FAST_FORWARD), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
}
|
||||
|
||||
setRepeatModeIcon(remoteViews, basePlayerImpl.getRepeatMode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the notification, and the play/pause button in it.
|
||||
* Used for changes on the remoteView
|
||||
*
|
||||
* @param drawableId if != -1, sets the drawable with that id on the play/pause button
|
||||
*/
|
||||
private synchronized void updateNotification(final int drawableId) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
notificationManager.notify(NOTIFICATION_ID, notBuilder.build());
|
||||
timesNotificationUpdated++;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void setRepeatModeIcon(final RemoteViews remoteViews, final int repeatMode) {
|
||||
switch (repeatMode) {
|
||||
case Player.REPEAT_MODE_OFF:
|
||||
remoteViews.setInt(R.id.notificationRepeat, SET_IMAGE_RESOURCE_METHOD,
|
||||
R.drawable.exo_controls_repeat_off);
|
||||
break;
|
||||
case Player.REPEAT_MODE_ONE:
|
||||
remoteViews.setInt(R.id.notificationRepeat, SET_IMAGE_RESOURCE_METHOD,
|
||||
R.drawable.exo_controls_repeat_one);
|
||||
break;
|
||||
case Player.REPEAT_MODE_ALL:
|
||||
remoteViews.setInt(R.id.notificationRepeat, SET_IMAGE_RESOURCE_METHOD,
|
||||
R.drawable.exo_controls_repeat_all);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected class BasePlayerImpl extends BasePlayer {
|
||||
@NonNull
|
||||
private final AudioPlaybackResolver resolver;
|
||||
private int cachedDuration;
|
||||
private String cachedDurationString;
|
||||
|
||||
BasePlayerImpl(final Context context) {
|
||||
super(context);
|
||||
@ -367,51 +196,49 @@ public final class BackgroundPlayer extends Service {
|
||||
@Override
|
||||
public void handleIntent(final Intent intent) {
|
||||
super.handleIntent(intent);
|
||||
|
||||
resetNotification();
|
||||
if (bigNotRemoteView != null) {
|
||||
bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ handleIntent()");
|
||||
}
|
||||
if (notRemoteView != null) {
|
||||
notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
||||
}
|
||||
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences, true); // false
|
||||
NotificationUtil.getInstance().setProgressbarOnOldNotifications(100, 0, false);
|
||||
startForeground(NotificationUtil.NOTIFICATION_ID_BACKGROUND,
|
||||
NotificationUtil.getInstance().notificationBuilder.build());
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Thumbnail Loading
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void updateNotificationThumbnail() {
|
||||
if (basePlayerImpl == null) {
|
||||
return;
|
||||
}
|
||||
if (notRemoteView != null) {
|
||||
notRemoteView.setImageViewBitmap(R.id.notificationCover,
|
||||
basePlayerImpl.getThumbnail());
|
||||
}
|
||||
if (bigNotRemoteView != null) {
|
||||
bigNotRemoteView.setImageViewBitmap(R.id.notificationCover,
|
||||
basePlayerImpl.getThumbnail());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingComplete(final String imageUri, final View view,
|
||||
final Bitmap loadedImage) {
|
||||
super.onLoadingComplete(imageUri, view, loadedImage);
|
||||
resetNotification();
|
||||
updateNotificationThumbnail();
|
||||
updateNotification(-1);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onLoadingComplete()");
|
||||
}
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences, true); //true
|
||||
NotificationUtil.getInstance().updateOldNotificationsThumbnail(basePlayerImpl);
|
||||
NotificationUtil.getInstance().updateBackgroundPlayerNotification(-1,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingFailed(final String imageUri, final View view,
|
||||
final FailReason failReason) {
|
||||
super.onLoadingFailed(imageUri, view, failReason);
|
||||
resetNotification();
|
||||
updateNotificationThumbnail();
|
||||
updateNotification(-1);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onLoadingFailed()");
|
||||
}
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences, true); //true
|
||||
NotificationUtil.getInstance().updateOldNotificationsThumbnail(basePlayerImpl);
|
||||
NotificationUtil.getInstance().updateBackgroundPlayerNotification(-1,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -426,6 +253,14 @@ public final class BackgroundPlayer extends Service {
|
||||
@Override
|
||||
public void onShuffleClicked() {
|
||||
super.onShuffleClicked();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onShuffleClicked:");
|
||||
}
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance().updateBackgroundPlayerNotification(-1,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
updatePlayback();
|
||||
}
|
||||
|
||||
@ -440,31 +275,35 @@ public final class BackgroundPlayer extends Service {
|
||||
final int bufferPercent) {
|
||||
updateProgress(currentProgress, duration, bufferPercent);
|
||||
|
||||
if (!shouldUpdateOnProgress) {
|
||||
return;
|
||||
}
|
||||
if (timesNotificationUpdated > NOTIFICATION_UPDATES_BEFORE_RESET) {
|
||||
resetNotification();
|
||||
// setMetadata only updates the metadata when any of the metadata keys are null
|
||||
basePlayerImpl.mediaSessionManager.setMetadata(basePlayerImpl.getVideoTitle(),
|
||||
basePlayerImpl.getUploaderName(), basePlayerImpl.getThumbnail(), duration);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /*Oreo*/) {
|
||||
updateNotificationThumbnail();
|
||||
boolean areOldNotificationsEnabled = sharedPreferences.getBoolean(
|
||||
getString(R.string.enable_old_notifications_key), false);
|
||||
if (areOldNotificationsEnabled) {
|
||||
if (!shouldUpdateOnProgress) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (bigNotRemoteView != null) {
|
||||
if (cachedDuration != duration) {
|
||||
cachedDuration = duration;
|
||||
cachedDurationString = getTimeString(duration);
|
||||
if (NotificationUtil.timesNotificationUpdated
|
||||
> NotificationUtil.NOTIFICATION_UPDATES_BEFORE_RESET) {
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationUtil.getInstance()
|
||||
.updateOldNotificationsThumbnail(basePlayerImpl);
|
||||
}
|
||||
}
|
||||
bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, duration,
|
||||
|
||||
NotificationUtil.getInstance().setCachedDuration(currentProgress, duration);
|
||||
NotificationUtil.getInstance().setProgressbarOnOldNotifications(duration,
|
||||
currentProgress, false);
|
||||
bigNotRemoteView.setTextViewText(R.id.notificationTime,
|
||||
getTimeString(currentProgress) + " / " + cachedDurationString);
|
||||
|
||||
NotificationUtil.getInstance().updateBackgroundPlayerNotification(-1,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
}
|
||||
if (notRemoteView != null) {
|
||||
notRemoteView.setProgressBar(R.id.notificationProgressBar, duration,
|
||||
currentProgress, false);
|
||||
}
|
||||
updateNotification(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -482,12 +321,7 @@ 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);
|
||||
}
|
||||
NotificationUtil.getInstance().unsetImageInOldNotifications();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -507,8 +341,14 @@ public final class BackgroundPlayer extends Service {
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged(final int i) {
|
||||
resetNotification();
|
||||
updateNotification(-1);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onRepeatModeChanged()");
|
||||
}
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance().updateBackgroundPlayerNotification(-1,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
updatePlayback();
|
||||
}
|
||||
|
||||
@ -518,9 +358,15 @@ public final class BackgroundPlayer extends Service {
|
||||
|
||||
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
|
||||
super.onMetadataChanged(tag);
|
||||
resetNotification();
|
||||
updateNotificationThumbnail();
|
||||
updateNotification(-1);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onMetadataChanged()");
|
||||
}
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance().updateOldNotificationsThumbnail(basePlayerImpl);
|
||||
NotificationUtil.getInstance().updateBackgroundPlayerNotification(-1,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
updateMetadata();
|
||||
}
|
||||
|
||||
@ -585,31 +431,36 @@ public final class BackgroundPlayer extends Service {
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
protected void setupBroadcastReceiver(final IntentFilter intentFltr) {
|
||||
super.setupBroadcastReceiver(intentFltr);
|
||||
intentFltr.addAction(ACTION_CLOSE);
|
||||
intentFltr.addAction(ACTION_PLAY_PAUSE);
|
||||
intentFltr.addAction(ACTION_REPEAT);
|
||||
intentFltr.addAction(ACTION_PLAY_PREVIOUS);
|
||||
intentFltr.addAction(ACTION_PLAY_NEXT);
|
||||
intentFltr.addAction(ACTION_FAST_REWIND);
|
||||
intentFltr.addAction(ACTION_FAST_FORWARD);
|
||||
protected void setupBroadcastReceiver(final IntentFilter intentFilter) {
|
||||
super.setupBroadcastReceiver(intentFilter);
|
||||
intentFilter.addAction(ACTION_CLOSE);
|
||||
intentFilter.addAction(ACTION_PLAY_PAUSE);
|
||||
intentFilter.addAction(ACTION_REPEAT);
|
||||
intentFilter.addAction(ACTION_PLAY_PREVIOUS);
|
||||
intentFilter.addAction(ACTION_PLAY_NEXT);
|
||||
intentFilter.addAction(ACTION_FAST_REWIND);
|
||||
intentFilter.addAction(ACTION_FAST_FORWARD);
|
||||
intentFilter.addAction(ACTION_BUFFERING);
|
||||
intentFilter.addAction(ACTION_SHUFFLE);
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
|
||||
intentFltr.addAction(Intent.ACTION_SCREEN_ON);
|
||||
intentFltr.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
|
||||
intentFltr.addAction(Intent.ACTION_HEADSET_PLUG);
|
||||
intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBroadcastReceived(final Intent intent) {
|
||||
super.onBroadcastReceived(intent);
|
||||
|
||||
if (intent == null || intent.getAction() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onBroadcastReceived() called with: intent = [" + intent + "]");
|
||||
// FIXME remove N_
|
||||
Log.d(TAG, "N_ onBroadcastReceived() called with: intent = [" + intent + "]");
|
||||
}
|
||||
|
||||
switch (intent.getAction()) {
|
||||
case ACTION_CLOSE:
|
||||
onClose();
|
||||
@ -627,9 +478,11 @@ public final class BackgroundPlayer extends Service {
|
||||
onPlayPrevious();
|
||||
break;
|
||||
case ACTION_FAST_FORWARD:
|
||||
isForwardPressed = true;
|
||||
onFastForward();
|
||||
break;
|
||||
case ACTION_FAST_REWIND:
|
||||
isRewindPressed = true;
|
||||
onFastRewind();
|
||||
break;
|
||||
case Intent.ACTION_SCREEN_ON:
|
||||
@ -638,6 +491,17 @@ public final class BackgroundPlayer extends Service {
|
||||
case Intent.ACTION_SCREEN_OFF:
|
||||
onScreenOnOff(false);
|
||||
break;
|
||||
case ACTION_BUFFERING:
|
||||
onBuffering();
|
||||
break;
|
||||
case ACTION_SHUFFLE:
|
||||
onShuffleClicked();
|
||||
break;
|
||||
case "android.intent.action.HEADSET_PLUG": //FIXME
|
||||
/*notificationManager.cancel(NOTIFICATION_ID);
|
||||
mediaSessionManager.dispose();
|
||||
mediaSessionManager.enable(getBaseContext(), basePlayerImpl.simpleExoPlayer);*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -645,6 +509,31 @@ public final class BackgroundPlayer extends Service {
|
||||
// States
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onBuffering() {
|
||||
super.onBuffering();
|
||||
if (NotificationUtil.getInstance().notificationSlot0.contains("buffering")
|
||||
|| NotificationUtil.getInstance().notificationSlot1.contains("buffering")
|
||||
|| NotificationUtil.getInstance().notificationSlot2.contains("buffering")
|
||||
|| NotificationUtil.getInstance().notificationSlot3.contains("buffering")
|
||||
|| NotificationUtil.getInstance().notificationSlot4.contains("buffering")) {
|
||||
if (basePlayerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
|
||||
|| basePlayerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
|
||||
|| basePlayerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
|
||||
if (!(isForwardPressed || isRewindPressed)) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onBuffering()");
|
||||
}
|
||||
NotificationUtil.getInstance().updateBackgroundPlayerNotification(-1,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
} else {
|
||||
isForwardPressed = false;
|
||||
isRewindPressed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeState(final int state) {
|
||||
super.changeState(state);
|
||||
@ -654,31 +543,50 @@ public final class BackgroundPlayer extends Service {
|
||||
@Override
|
||||
public void onPlaying() {
|
||||
super.onPlaying();
|
||||
resetNotification();
|
||||
updateNotificationThumbnail();
|
||||
updateNotification(R.drawable.exo_controls_pause);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onPlaying()");
|
||||
}
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance().updateOldNotificationsThumbnail(basePlayerImpl);
|
||||
NotificationUtil.getInstance()
|
||||
.updateBackgroundPlayerNotification(R.drawable.ic_pause_white_24dp,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPaused() {
|
||||
super.onPaused();
|
||||
resetNotification();
|
||||
updateNotificationThumbnail();
|
||||
updateNotification(R.drawable.exo_controls_play);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onPaused()");
|
||||
}
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance().updateOldNotificationsThumbnail(basePlayerImpl);
|
||||
NotificationUtil.getInstance()
|
||||
.updateBackgroundPlayerNotification(R.drawable.ic_play_arrow_white_24dp,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
super.onCompleted();
|
||||
resetNotification();
|
||||
if (bigNotRemoteView != null) {
|
||||
bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 100, false);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onCompleted()");
|
||||
}
|
||||
if (notRemoteView != null) {
|
||||
notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 100, false);
|
||||
}
|
||||
updateNotificationThumbnail();
|
||||
updateNotification(R.drawable.ic_replay_white_24dp);
|
||||
|
||||
NotificationUtil.getInstance().recreateBackgroundPlayerNotification(context,
|
||||
basePlayerImpl.mediaSessionManager.getSessionToken(), basePlayerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance().setProgressbarOnOldNotifications(100, 100, false);
|
||||
NotificationUtil.getInstance().updateOldNotificationsThumbnail(basePlayerImpl);
|
||||
NotificationUtil.getInstance()
|
||||
.updateBackgroundPlayerNotification(R.drawable.ic_replay_white_24dp,
|
||||
getBaseContext(), basePlayerImpl, sharedPreferences);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1379
app/src/main/java/org/schabi/newpipe/player/NotificationUtil.java
Normal file
@ -22,8 +22,6 @@ package org.schabi.newpipe.player;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -48,23 +46,19 @@ import android.view.animation.AnticipateInterpolator;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.text.CaptionStyleCompat;
|
||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||
|
||||
import org.schabi.newpipe.BuildConfig;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.schabi.newpipe.player.event.PlayerEventListener;
|
||||
@ -89,13 +83,28 @@ import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||
* @author mauriciocolli
|
||||
*/
|
||||
public final class PopupVideoPlayer extends Service {
|
||||
public static final String ACTION_CLOSE = "org.schabi.newpipe.player.PopupVideoPlayer.CLOSE";
|
||||
public static final String ACTION_PLAY_PAUSE
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.PLAY_PAUSE";
|
||||
public static final String ACTION_REPEAT = "org.schabi.newpipe.player.PopupVideoPlayer.REPEAT";
|
||||
private static final String TAG = ".PopupVideoPlayer";
|
||||
private static final boolean DEBUG = BasePlayer.DEBUG;
|
||||
private static final int NOTIFICATION_ID = 40028922;
|
||||
|
||||
public static final String ACTION_CLOSE
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.CLOSE";
|
||||
public static final String ACTION_PLAY_PAUSE
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.PLAY_PAUSE";
|
||||
public static final String ACTION_REPEAT
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.REPEAT";
|
||||
public static final String ACTION_FAST_REWIND
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.ACTION_FAST_REWIND";
|
||||
public static final String ACTION_FAST_FORWARD
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.ACTION_FAST_FORWARD";
|
||||
public static final String ACTION_PLAY_NEXT
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.ACTION_PLAY_NEXT";
|
||||
public static final String ACTION_PLAY_PREVIOUS
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.ACTION_PLAY_PREVIOUS";
|
||||
public static final String ACTION_BUFFERING
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.ACTION_BUFFERING";
|
||||
public static final String ACTION_SHUFFLE
|
||||
= "org.schabi.newpipe.player.PopupVideoPlayer.ACTION_SHUFFLE";
|
||||
|
||||
private static final String POPUP_SAVED_WIDTH = "popup_saved_width";
|
||||
private static final String POPUP_SAVED_X = "popup_saved_x";
|
||||
private static final String POPUP_SAVED_Y = "popup_saved_y";
|
||||
@ -126,12 +135,12 @@ public final class PopupVideoPlayer extends Service {
|
||||
private float maximumWidth;
|
||||
private float maximumHeight;
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder notBuilder;
|
||||
private RemoteViews notRemoteView;
|
||||
private boolean isForwardPressed;
|
||||
private boolean isRewindPressed;
|
||||
|
||||
private VideoPlayerImpl playerImpl;
|
||||
private boolean isPopupClosing = false;
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Service-Activity Binder
|
||||
@ -148,7 +157,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
public void onCreate() {
|
||||
assureCorrectAppLanguage(this);
|
||||
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
|
||||
notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
|
||||
playerImpl = new VideoPlayerImpl(this);
|
||||
ThemeHelper.setTheme(this);
|
||||
@ -220,9 +229,9 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
final boolean popupRememberSizeAndPos = PlayerHelper.isRememberingPopupDimensions(this);
|
||||
final float defaultSize = getResources().getDimension(R.dimen.popup_default_width);
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
popupWidth = popupRememberSizeAndPos
|
||||
? sharedPreferences.getFloat(POPUP_SAVED_WIDTH, defaultSize) : defaultSize;
|
||||
? sharedPrefs.getFloat(POPUP_SAVED_WIDTH, defaultSize) : defaultSize;
|
||||
|
||||
final int layoutParamType = Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O
|
||||
? WindowManager.LayoutParams.TYPE_PHONE
|
||||
@ -236,16 +245,16 @@ public final class PopupVideoPlayer extends Service {
|
||||
popupLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
|
||||
popupLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
|
||||
|
||||
int centerX = (int) (screenWidth / 2f - popupWidth / 2f);
|
||||
int centerY = (int) (screenHeight / 2f - popupHeight / 2f);
|
||||
final int centerX = (int) (screenWidth / 2f - popupWidth / 2f);
|
||||
final int centerY = (int) (screenHeight / 2f - popupHeight / 2f);
|
||||
popupLayoutParams.x = popupRememberSizeAndPos
|
||||
? sharedPreferences.getInt(POPUP_SAVED_X, centerX) : centerX;
|
||||
? sharedPrefs.getInt(POPUP_SAVED_X, centerX) : centerX;
|
||||
popupLayoutParams.y = popupRememberSizeAndPos
|
||||
? sharedPreferences.getInt(POPUP_SAVED_Y, centerY) : centerY;
|
||||
? sharedPrefs.getInt(POPUP_SAVED_Y, centerY) : centerY;
|
||||
|
||||
checkPopupPositionBounds();
|
||||
|
||||
PopupWindowGestureListener listener = new PopupWindowGestureListener();
|
||||
final PopupWindowGestureListener listener = new PopupWindowGestureListener();
|
||||
popupGestureDetector = new GestureDetector(this, listener);
|
||||
rootView.setOnTouchListener(listener);
|
||||
|
||||
@ -282,71 +291,6 @@ public final class PopupVideoPlayer extends Service {
|
||||
windowManager.addView(closeOverlayView, closeOverlayLayoutParams);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Notification
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void resetNotification() {
|
||||
notBuilder = createNotification();
|
||||
}
|
||||
|
||||
private NotificationCompat.Builder createNotification() {
|
||||
notRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
|
||||
R.layout.player_popup_notification);
|
||||
|
||||
notRemoteView.setTextViewText(R.id.notificationSongName, playerImpl.getVideoTitle());
|
||||
notRemoteView.setTextViewText(R.id.notificationArtist, playerImpl.getUploaderName());
|
||||
notRemoteView.setImageViewBitmap(R.id.notificationCover, playerImpl.getThumbnail());
|
||||
|
||||
notRemoteView.setOnClickPendingIntent(R.id.notificationPlayPause,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
notRemoteView.setOnClickPendingIntent(R.id.notificationStop,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
notRemoteView.setOnClickPendingIntent(R.id.notificationRepeat,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
|
||||
// Starts popup player activity -- attempts to unlock lockscreen
|
||||
final Intent intent = NavigationHelper.getPopupPlayerActivityIntent(this);
|
||||
notRemoteView.setOnClickPendingIntent(R.id.notificationContent,
|
||||
PendingIntent.getActivity(this, NOTIFICATION_ID, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
|
||||
setRepeatModeRemote(notRemoteView, playerImpl.getRepeatMode());
|
||||
|
||||
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)
|
||||
.setContent(notRemoteView);
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
|
||||
builder.setPriority(NotificationCompat.PRIORITY_MAX);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the notification, and the play/pause button in it.
|
||||
* Used for changes on the remoteView
|
||||
*
|
||||
* @param drawableId if != -1, sets the drawable with that id on the play/pause button
|
||||
*/
|
||||
private void updateNotification(final int drawableId) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
|
||||
}
|
||||
if (notBuilder == null || notRemoteView == null) {
|
||||
return;
|
||||
}
|
||||
if (drawableId != -1) {
|
||||
notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
||||
}
|
||||
notificationManager.notify(NOTIFICATION_ID, notBuilder.build());
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@ -372,9 +316,8 @@ public final class PopupVideoPlayer extends Service {
|
||||
}
|
||||
|
||||
mBinder = null;
|
||||
if (notificationManager != null) {
|
||||
notificationManager.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
NotificationUtil.getInstance().cancelNotification(NotificationUtil.NOTIFICATION_ID_POPUP);
|
||||
|
||||
animateOverlayAndFinishService();
|
||||
}
|
||||
@ -461,11 +404,11 @@ public final class PopupVideoPlayer extends Service {
|
||||
}
|
||||
|
||||
private void savePositionAndSize() {
|
||||
SharedPreferences sharedPreferences = PreferenceManager
|
||||
final SharedPreferences sharedPrefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(PopupVideoPlayer.this);
|
||||
sharedPreferences.edit().putInt(POPUP_SAVED_X, popupLayoutParams.x).apply();
|
||||
sharedPreferences.edit().putInt(POPUP_SAVED_Y, popupLayoutParams.y).apply();
|
||||
sharedPreferences.edit().putFloat(POPUP_SAVED_WIDTH, popupLayoutParams.width).apply();
|
||||
sharedPrefs.edit().putInt(POPUP_SAVED_X, popupLayoutParams.x).apply();
|
||||
sharedPrefs.edit().putInt(POPUP_SAVED_Y, popupLayoutParams.y).apply();
|
||||
sharedPrefs.edit().putFloat(POPUP_SAVED_WIDTH, popupLayoutParams.width).apply();
|
||||
}
|
||||
|
||||
private float getMinimumVideoHeight(final float width) {
|
||||
@ -530,29 +473,6 @@ public final class PopupVideoPlayer extends Service {
|
||||
windowManager.updateViewLayout(playerImpl.getRootView(), popupLayoutParams);
|
||||
}
|
||||
|
||||
protected void setRepeatModeRemote(final RemoteViews remoteViews, final int repeatMode) {
|
||||
final String methodName = "setImageResource";
|
||||
|
||||
if (remoteViews == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (repeatMode) {
|
||||
case Player.REPEAT_MODE_OFF:
|
||||
remoteViews.setInt(R.id.notificationRepeat, methodName,
|
||||
R.drawable.exo_controls_repeat_off);
|
||||
break;
|
||||
case Player.REPEAT_MODE_ONE:
|
||||
remoteViews.setInt(R.id.notificationRepeat, methodName,
|
||||
R.drawable.exo_controls_repeat_one);
|
||||
break;
|
||||
case Player.REPEAT_MODE_ALL:
|
||||
remoteViews.setInt(R.id.notificationRepeat, methodName,
|
||||
R.drawable.exo_controls_repeat_all);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWindowFlags(final int flags) {
|
||||
if (popupLayoutParams == null || windowManager == null || playerImpl == null) {
|
||||
return;
|
||||
@ -579,8 +499,11 @@ public final class PopupVideoPlayer extends Service {
|
||||
public void handleIntent(final Intent intent) {
|
||||
super.handleIntent(intent);
|
||||
|
||||
resetNotification();
|
||||
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl, sharedPreferences,
|
||||
true);
|
||||
startForeground(NotificationUtil.NOTIFICATION_ID_POPUP,
|
||||
NotificationUtil.getInstance().notificationBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -622,9 +545,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (notRemoteView != null) {
|
||||
notRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
||||
}
|
||||
NotificationUtil.getInstance().unsetImageInOldPopupNotifications();
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
@ -683,6 +604,11 @@ public final class PopupVideoPlayer extends Service {
|
||||
@Override
|
||||
public void onShuffleClicked() {
|
||||
super.onShuffleClicked();
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance().updatePopupPlayerNotification(-1,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
updatePlayback();
|
||||
}
|
||||
|
||||
@ -697,6 +623,10 @@ public final class PopupVideoPlayer extends Service {
|
||||
final int bufferPercent) {
|
||||
updateProgress(currentProgress, duration, bufferPercent);
|
||||
super.onUpdateProgress(currentProgress, duration, bufferPercent);
|
||||
|
||||
// setMetadata only updates the metadata when any of the metadata keys are null
|
||||
playerImpl.mediaSessionManager.setMetadata(playerImpl.getVideoTitle(),
|
||||
playerImpl.getUploaderName(), playerImpl.getThumbnail(), duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -724,28 +654,38 @@ public final class PopupVideoPlayer extends Service {
|
||||
public void onLoadingComplete(final String imageUri, final View view,
|
||||
final Bitmap loadedImage) {
|
||||
super.onLoadingComplete(imageUri, view, loadedImage);
|
||||
|
||||
if (playerImpl == null) {
|
||||
return;
|
||||
}
|
||||
// rebuild notification here since remote view does not release bitmaps,
|
||||
// rebuild (old) notification here since remote view does not release bitmaps,
|
||||
// causing memory leaks
|
||||
resetNotification();
|
||||
updateNotification(-1);
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl, sharedPreferences,
|
||||
true);
|
||||
NotificationUtil.getInstance().updatePopupPlayerNotification(-1,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingFailed(final String imageUri, final View view,
|
||||
final FailReason failReason) {
|
||||
super.onLoadingFailed(imageUri, view, failReason);
|
||||
resetNotification();
|
||||
updateNotification(-1);
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl, sharedPreferences,
|
||||
true);
|
||||
NotificationUtil.getInstance().updatePopupPlayerNotification(-1,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingCancelled(final String imageUri, final View view) {
|
||||
super.onLoadingCancelled(imageUri, view);
|
||||
resetNotification();
|
||||
updateNotification(-1);
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl, sharedPreferences,
|
||||
true);
|
||||
NotificationUtil.getInstance().updatePopupPlayerNotification(-1,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -799,10 +739,12 @@ public final class PopupVideoPlayer extends Service {
|
||||
@Override
|
||||
public void onRepeatModeChanged(final int i) {
|
||||
super.onRepeatModeChanged(i);
|
||||
setRepeatModeRemote(notRemoteView, i);
|
||||
updatePlayback();
|
||||
resetNotification();
|
||||
updateNotification(-1);
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance().updatePopupPlayerNotification(-1,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -817,8 +759,11 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
|
||||
super.onMetadataChanged(tag);
|
||||
resetNotification();
|
||||
updateNotification(-1);
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance().updatePopupPlayerNotification(-1,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
updateMetadata();
|
||||
}
|
||||
|
||||
@ -833,18 +778,25 @@ public final class PopupVideoPlayer extends Service {
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
protected void setupBroadcastReceiver(final IntentFilter intentFltr) {
|
||||
super.setupBroadcastReceiver(intentFltr);
|
||||
|
||||
protected void setupBroadcastReceiver(final IntentFilter intentFilter) {
|
||||
super.setupBroadcastReceiver(intentFilter);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "setupBroadcastReceiver() called with: "
|
||||
+ "intentFilter = [" + intentFltr + "]");
|
||||
+ "intentFilter = [" + intentFilter + "]");
|
||||
}
|
||||
intentFltr.addAction(ACTION_CLOSE);
|
||||
intentFltr.addAction(ACTION_PLAY_PAUSE);
|
||||
intentFltr.addAction(ACTION_REPEAT);
|
||||
intentFilter.addAction(ACTION_CLOSE);
|
||||
intentFilter.addAction(ACTION_PLAY_PAUSE);
|
||||
intentFilter.addAction(ACTION_REPEAT);
|
||||
intentFilter.addAction(ACTION_PLAY_PREVIOUS);
|
||||
intentFilter.addAction(ACTION_PLAY_NEXT);
|
||||
intentFilter.addAction(ACTION_FAST_REWIND);
|
||||
intentFilter.addAction(ACTION_FAST_FORWARD);
|
||||
intentFilter.addAction(ACTION_BUFFERING);
|
||||
intentFilter.addAction(ACTION_SHUFFLE);
|
||||
|
||||
intentFltr.addAction(Intent.ACTION_SCREEN_ON);
|
||||
intentFltr.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -872,6 +824,26 @@ public final class PopupVideoPlayer extends Service {
|
||||
case Intent.ACTION_SCREEN_OFF:
|
||||
enableVideoRenderer(false);
|
||||
break;
|
||||
case ACTION_PLAY_NEXT:
|
||||
onPlayNext();
|
||||
break;
|
||||
case ACTION_PLAY_PREVIOUS:
|
||||
onPlayPrevious();
|
||||
break;
|
||||
case ACTION_FAST_FORWARD:
|
||||
isForwardPressed = true;
|
||||
onFastForward();
|
||||
break;
|
||||
case ACTION_FAST_REWIND:
|
||||
isRewindPressed = true;
|
||||
onFastRewind();
|
||||
break;
|
||||
case ACTION_BUFFERING:
|
||||
onBuffering();
|
||||
break;
|
||||
case ACTION_SHUFFLE:
|
||||
onShuffleClicked();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -888,8 +860,13 @@ public final class PopupVideoPlayer extends Service {
|
||||
@Override
|
||||
public void onBlocked() {
|
||||
super.onBlocked();
|
||||
resetNotification();
|
||||
updateNotification(R.drawable.exo_controls_play);
|
||||
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance()
|
||||
.updatePopupPlayerNotification(R.drawable.ic_play_arrow_white_24dp,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -898,20 +875,48 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
updateWindowFlags(ONGOING_PLAYBACK_WINDOW_FLAGS);
|
||||
|
||||
resetNotification();
|
||||
updateNotification(R.drawable.exo_controls_pause);
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance()
|
||||
.updatePopupPlayerNotification(R.drawable.ic_pause_white_24dp, getBaseContext(),
|
||||
playerImpl, sharedPreferences);
|
||||
|
||||
videoPlayPause.setBackgroundResource(R.drawable.exo_controls_pause);
|
||||
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||
|
||||
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||
startForeground(NotificationUtil.NOTIFICATION_ID_POPUP,
|
||||
NotificationUtil.getInstance().notificationBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBuffering() {
|
||||
super.onBuffering();
|
||||
resetNotification();
|
||||
updateNotification(R.drawable.exo_controls_play);
|
||||
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl,
|
||||
sharedPreferences);
|
||||
if (NotificationUtil.getInstance().notificationSlot0.contains("buffering")
|
||||
|| NotificationUtil.getInstance().notificationSlot1.contains("buffering")
|
||||
|| NotificationUtil.getInstance().notificationSlot2.contains("buffering")
|
||||
|| NotificationUtil.getInstance().notificationSlot3.contains("buffering")
|
||||
|| NotificationUtil.getInstance().notificationSlot4.contains("buffering")) {
|
||||
if (playerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
|
||||
|| playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
|
||||
|| playerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
|
||||
if (!(isForwardPressed || isRewindPressed)) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "N_ onBuffering()");
|
||||
}
|
||||
NotificationUtil.getInstance()
|
||||
.updatePopupPlayerNotification(R.drawable.ic_play_arrow_white_24dp,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
} else {
|
||||
isForwardPressed = false;
|
||||
isRewindPressed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -920,9 +925,14 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
updateWindowFlags(IDLE_WINDOW_FLAGS);
|
||||
|
||||
resetNotification();
|
||||
updateNotification(R.drawable.exo_controls_play);
|
||||
videoPlayPause.setBackgroundResource(R.drawable.exo_controls_play);
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance()
|
||||
.updatePopupPlayerNotification(R.drawable.ic_play_arrow_white_24dp,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
|
||||
videoPlayPause.setBackgroundResource(R.drawable.ic_play_arrow_white_24dp);
|
||||
|
||||
stopForeground(false);
|
||||
}
|
||||
@ -930,8 +940,13 @@ public final class PopupVideoPlayer extends Service {
|
||||
@Override
|
||||
public void onPausedSeek() {
|
||||
super.onPausedSeek();
|
||||
resetNotification();
|
||||
updateNotification(R.drawable.exo_controls_play);
|
||||
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance()
|
||||
.updatePopupPlayerNotification(R.drawable.ic_play_arrow_white_24dp,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
|
||||
videoPlayPause.setBackgroundResource(R.drawable.exo_controls_play);
|
||||
}
|
||||
@ -942,8 +957,13 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
updateWindowFlags(IDLE_WINDOW_FLAGS);
|
||||
|
||||
resetNotification();
|
||||
updateNotification(R.drawable.ic_replay_white_24dp);
|
||||
NotificationUtil.getInstance().recreatePopupPlayerNotification(context,
|
||||
playerImpl.mediaSessionManager.getSessionToken(), playerImpl,
|
||||
sharedPreferences);
|
||||
NotificationUtil.getInstance()
|
||||
.updatePopupPlayerNotification(R.drawable.ic_replay_white_24dp,
|
||||
getBaseContext(), playerImpl, sharedPreferences);
|
||||
|
||||
videoPlayPause.setBackgroundResource(R.drawable.ic_replay_white_24dp);
|
||||
|
||||
stopForeground(false);
|
||||
@ -1004,7 +1024,6 @@ public final class PopupVideoPlayer extends Service {
|
||||
private float initSecPointerX = -1;
|
||||
private float initSecPointerY = -1;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onDoubleTap(final MotionEvent e) {
|
||||
if (DEBUG) {
|
||||
|
@ -3,17 +3,14 @@ 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.v4.media.MediaMetadataCompat;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.media.app.NotificationCompat.MediaStyle;
|
||||
import androidx.media.session.MediaButtonReceiver;
|
||||
|
||||
import com.google.android.exoplayer2.Player;
|
||||
@ -30,13 +27,29 @@ public class MediaSessionManager {
|
||||
private final MediaSessionCompat mediaSession;
|
||||
@NonNull
|
||||
private final MediaSessionConnector sessionConnector;
|
||||
@NonNull
|
||||
private final PlaybackStateCompat.Builder playbackStateCompatBuilder;
|
||||
|
||||
private int tmpThumbHash;
|
||||
|
||||
public MediaSessionManager(@NonNull final Context context,
|
||||
@NonNull final Player player,
|
||||
@NonNull final MediaSessionCallback callback) {
|
||||
this.mediaSession = new MediaSessionCompat(context, TAG);
|
||||
this.mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
|
||||
| MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
||||
this.mediaSession.setActive(true);
|
||||
|
||||
this.playbackStateCompatBuilder = new PlaybackStateCompat.Builder();
|
||||
this.playbackStateCompatBuilder.setState(PlaybackStateCompat.STATE_NONE, -1, 1);
|
||||
this.playbackStateCompatBuilder.setActions(PlaybackStateCompat.ACTION_SEEK_TO
|
||||
| PlaybackStateCompat.ACTION_PLAY
|
||||
| PlaybackStateCompat.ACTION_PAUSE // was play and pause now play/pause
|
||||
| PlaybackStateCompat.ACTION_SKIP_TO_NEXT
|
||||
| PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
|
||||
| PlaybackStateCompat.ACTION_SET_REPEAT_MODE | PlaybackStateCompat.ACTION_STOP);
|
||||
this.mediaSession.setPlaybackState(playbackStateCompatBuilder.build());
|
||||
|
||||
this.sessionConnector = new MediaSessionConnector(mediaSession);
|
||||
this.sessionConnector.setControlDispatcher(new PlayQueuePlaybackController(callback));
|
||||
this.sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, callback));
|
||||
@ -49,37 +62,65 @@ public class MediaSessionManager {
|
||||
return MediaButtonReceiver.handleIntent(mediaSession, intent);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public void setLockScreenArt(final NotificationCompat.Builder builder,
|
||||
@Nullable final Bitmap thumbnailBitmap) {
|
||||
if (thumbnailBitmap == null || !mediaSession.isActive()) {
|
||||
public MediaSessionCompat.Token getSessionToken() {
|
||||
return this.mediaSession.getSessionToken();
|
||||
}
|
||||
|
||||
public void setMetadata(final String title, final String artist, final Bitmap albumArt,
|
||||
final long duration) {
|
||||
if (albumArt == null || !mediaSession.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mediaSession.setMetadata(
|
||||
new MediaMetadataCompat.Builder()
|
||||
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, thumbnailBitmap)
|
||||
.build()
|
||||
);
|
||||
if (getMetadataAlbumArt() == null) {
|
||||
Log.d(TAG, "N_getMetadataAlbumArt: thumb == null");
|
||||
}
|
||||
if (getMetadataTitle() == null) {
|
||||
Log.d(TAG, "N_getMetadataTitle: title == null");
|
||||
}
|
||||
if (getMetadataArtist() == null) {
|
||||
Log.d(TAG, "N_getMetadataArtist: artist == null");
|
||||
}
|
||||
if (getMetadataDuration() <= 1) {
|
||||
Log.d(TAG, "N_getMetadataDuration: duration <= 1; " + getMetadataDuration());
|
||||
}
|
||||
|
||||
MediaStyle mediaStyle = new MediaStyle()
|
||||
.setMediaSession(mediaSession.getSessionToken());
|
||||
|
||||
builder.setStyle(mediaStyle);
|
||||
if (getMetadataAlbumArt() == null || getMetadataTitle() == null
|
||||
|| getMetadataArtist() == null || getMetadataDuration() <= 1
|
||||
|| albumArt.hashCode() != tmpThumbHash) {
|
||||
Log.d(TAG, "setMetadata: N_Metadata update: t: " + title + " a: " + artist
|
||||
+ " thumb: " + albumArt.hashCode() + " d: " + duration);
|
||||
mediaSession.setMetadata(
|
||||
new MediaMetadataCompat.Builder()
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
|
||||
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt)
|
||||
.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, albumArt)
|
||||
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration)
|
||||
.build()
|
||||
);
|
||||
tmpThumbHash = albumArt.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public void clearLockScreenArt(final NotificationCompat.Builder builder) {
|
||||
mediaSession.setMetadata(
|
||||
new MediaMetadataCompat.Builder()
|
||||
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, null)
|
||||
.build()
|
||||
);
|
||||
private Bitmap getMetadataAlbumArt() {
|
||||
return mediaSession.getController().getMetadata()
|
||||
.getBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART);
|
||||
}
|
||||
|
||||
MediaStyle mediaStyle = new MediaStyle()
|
||||
.setMediaSession(mediaSession.getSessionToken());
|
||||
private String getMetadataTitle() {
|
||||
return mediaSession.getController().getMetadata()
|
||||
.getString(MediaMetadataCompat.METADATA_KEY_TITLE);
|
||||
}
|
||||
|
||||
builder.setStyle(mediaStyle);
|
||||
private String getMetadataArtist() {
|
||||
return mediaSession.getController().getMetadata()
|
||||
.getString(MediaMetadataCompat.METADATA_KEY_ARTIST);
|
||||
}
|
||||
|
||||
private long getMetadataDuration() {
|
||||
return mediaSession.getController().getMetadata()
|
||||
.getLong(MediaMetadataCompat.METADATA_KEY_DURATION);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,6 +11,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.player.NotificationUtil;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
|
||||
public class AppearanceSettingsFragment extends BasePreferenceFragment {
|
||||
@ -52,8 +53,22 @@ public class AppearanceSettingsFragment extends BasePreferenceFragment {
|
||||
final Preference captionSettings = findPreference(captionSettingsKey);
|
||||
getPreferenceScreen().removePreference(captionSettings);
|
||||
}
|
||||
|
||||
findPreference(getString(R.string.enable_old_notifications_key))
|
||||
.setOnPreferenceChangeListener(oldNotificationsOnPreferenceChangeListener);
|
||||
}
|
||||
|
||||
private Preference.OnPreferenceChangeListener oldNotificationsOnPreferenceChangeListener
|
||||
= (preference, newValue) -> {
|
||||
// NotificationUtil.getInstance().toast(getContext(),
|
||||
// "Killed background / popup player notification(s) !");
|
||||
NotificationUtil.getInstance()
|
||||
.cancelNotification(NotificationUtil.NOTIFICATION_ID_BACKGROUND);
|
||||
NotificationUtil.getInstance().cancelNotification(NotificationUtil.NOTIFICATION_ID_POPUP);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
||||
addPreferencesFromResource(R.xml.appearance_settings);
|
||||
|
BIN
app/src/main/res/drawable-hdpi/ic_close_white_32dp.png
Normal file
After Width: | Height: | Size: 257 B |
BIN
app/src/main/res/drawable-hdpi/ic_replay_white_32dp.png
Normal file
After Width: | Height: | Size: 804 B |
BIN
app/src/main/res/drawable-mdpi/ic_close_white_32dp.png
Normal file
After Width: | Height: | Size: 542 B |
BIN
app/src/main/res/drawable-mdpi/ic_replay_white_32dp.png
Normal file
After Width: | Height: | Size: 583 B |
BIN
app/src/main/res/drawable-xhdpi/ic_close_white_32dp.png
Normal file
After Width: | Height: | Size: 666 B |
BIN
app/src/main/res/drawable-xhdpi/ic_replay_white_32dp.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_close_white_32dp.png
Normal file
After Width: | Height: | Size: 436 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_replay_white_32dp.png
Normal file
After Width: | Height: | Size: 908 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_close_white_32dp.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_replay_white_32dp.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
@ -96,6 +96,113 @@
|
||||
<item>144p</item>
|
||||
</string-array>
|
||||
|
||||
<string name="enable_old_notifications_key" translatable="false">enable_old_notifications</string>
|
||||
<string name="settings_notifications_compact_view_key" translatable="false">notifications_compact_view</string>
|
||||
<string name="settings_notifications_compact_view_default_value" translatable="false">0,1,2</string>
|
||||
<string name="scale_to_square_image_in_notifications_key" translatable="false">scale_to_square_image_in_notifications</string>
|
||||
|
||||
<string name="notification_slot_prev_key" translatable="false">prev</string>
|
||||
<string name="notification_slot_next_key" translatable="false">next</string>
|
||||
<string name="notification_slot_rewind_key" translatable="false">rewind</string>
|
||||
<string name="notification_slot_forward_key" translatable="false">forward</string>
|
||||
<string name="notification_slot_smart_rewind_prev_key" translatable="false">smart_rewind_prev</string>
|
||||
<string name="notification_slot_smart_forward_next_key" translatable="false">smart_forward_next</string>
|
||||
<string name="notification_slot_play_pause_buffering_key" translatable="false">play_pause_buffering</string>
|
||||
<string name="notification_slot_play_pause_key" translatable="false">play_pause</string>
|
||||
<string name="notification_slot_repeat_key" translatable="false">repeat</string>
|
||||
<string name="notification_slot_shuffle_key" translatable="false">shuffle</string>
|
||||
<string name="notification_slot_close_key" translatable="false">close</string>
|
||||
<string name="notification_slot_n_a_key" translatable="false">n/a</string>
|
||||
|
||||
<string name="notification_slot_0_key" translatable="false">notification_slot_0_key</string>
|
||||
<string name="notification_slot_0_value" translatable="false">@string/notification_slot_smart_rewind_prev_key</string>
|
||||
<string-array name="notification_slot_0_description_list" translatable="false">
|
||||
<item>Rewind / Previous</item>
|
||||
<item>Previous</item>
|
||||
<item>Rewind</item>
|
||||
</string-array>
|
||||
<string-array name="notification_slot_0_values_list" translatable="false">
|
||||
<item>@string/notification_slot_smart_rewind_prev_key</item>
|
||||
<item>@string/notification_slot_prev_key</item>
|
||||
<item>@string/notification_slot_rewind_key</item>
|
||||
</string-array>
|
||||
|
||||
<string name="notification_slot_1_key" translatable="false">notification_slot_1_key</string>
|
||||
<string name="notification_slot_1_value" translatable="false">@string/notification_slot_play_pause_buffering_key</string>
|
||||
<string-array name="notification_slot_1_description_list" translatable="false">
|
||||
<item>Play / Pause / Buffering</item>
|
||||
<item>Play / Pause</item>
|
||||
<item>Rewind</item>
|
||||
</string-array>
|
||||
<string-array name="notification_slot_1_values_list" translatable="false">
|
||||
<item>@string/notification_slot_play_pause_buffering_key</item>
|
||||
<item>@string/notification_slot_play_pause_key</item>
|
||||
<item>@string/notification_slot_rewind_key</item>
|
||||
</string-array>
|
||||
|
||||
|
||||
<string name="notification_slot_2_key" translatable="false">notification_slot_2_key</string>
|
||||
<string name="notification_slot_2_value" translatable="false">@string/notification_slot_smart_forward_next_key</string>
|
||||
<string-array name="notification_slot_2_description_list" translatable="false">
|
||||
<item>Forward / Next</item>
|
||||
<item>Forward</item>
|
||||
<item>Next</item>
|
||||
<item>Play / Pause / Buffering</item>
|
||||
<item>Play / Pause</item>
|
||||
</string-array>
|
||||
<string-array name="notification_slot_2_values_list" translatable="false">
|
||||
<item>@string/notification_slot_smart_forward_next_key</item>
|
||||
<item>@string/notification_slot_forward_key</item>
|
||||
<item>@string/notification_slot_next_key</item>
|
||||
<item>@string/notification_slot_play_pause_buffering_key</item>
|
||||
<item>@string/notification_slot_play_pause_key</item>
|
||||
</string-array>
|
||||
|
||||
<string name="notification_slot_3_key" translatable="false">notification_slot_3_key</string>
|
||||
<string name="notification_slot_3_value" translatable="false">@string/notification_slot_repeat_key</string>
|
||||
<string-array name="notification_slot_3_description_list" translatable="false">
|
||||
<item>Repeat</item>
|
||||
<item>Shuffle</item>
|
||||
<item>Previous</item>
|
||||
<item>Forward</item>
|
||||
<item>Forward / Next</item>
|
||||
<item>Rewind</item>
|
||||
<item>Rewind / Previous</item>
|
||||
<item>Close</item>
|
||||
<item>N/A</item>
|
||||
</string-array>
|
||||
<string-array name="notification_slot_3_values_list" translatable="false">
|
||||
<item>@string/notification_slot_repeat_key</item>
|
||||
<item>@string/notification_slot_shuffle_key</item>
|
||||
<item>@string/notification_slot_prev_key</item>
|
||||
<item>@string/notification_slot_forward_key</item>
|
||||
<item>@string/notification_slot_smart_forward_next_key</item>
|
||||
<item>@string/notification_slot_rewind_key</item>
|
||||
<item>@string/notification_slot_smart_rewind_prev_key</item>
|
||||
<item>@string/notification_slot_close_key</item>
|
||||
<item>@string/notification_slot_n_a_key</item>
|
||||
</string-array>
|
||||
|
||||
<string name="notification_slot_4_key" translatable="false">notification_slot_4_key</string>
|
||||
<string name="notification_slot_4_value" translatable="false">@string/notification_slot_close_key</string>
|
||||
<string-array name="notification_slot_4_description_list" translatable="false">
|
||||
<item>Close</item>
|
||||
<item>Repeat</item>
|
||||
<item>Shuffle</item>
|
||||
<item>Next</item>
|
||||
<item>Forward</item>
|
||||
<item>Forward / Next</item>
|
||||
<item>N/A</item>
|
||||
</string-array>
|
||||
<string-array name="notification_slot_4_values_list" translatable="false">
|
||||
<item>@string/notification_slot_close_key</item>
|
||||
<item>@string/notification_slot_repeat_key</item>
|
||||
<item>@string/notification_slot_shuffle_key</item>
|
||||
<item>@string/notification_slot_next_key</item>
|
||||
<item>@string/notification_slot_forward_key</item>
|
||||
<item>@string/notification_slot_smart_forward_next_key</item>
|
||||
<item>@string/notification_slot_n_a_key</item>
|
||||
</string-array>
|
||||
|
||||
<string name="video_mp4_key" translatable="false">video_mp4</string>
|
||||
<string name="video_webm_key" translatable="false">video_webm</string>
|
||||
|
@ -57,9 +57,18 @@
|
||||
<string name="kore_not_found">Install missing Kore app?</string>
|
||||
<string name="kore_package" translatable="false">org.xbmc.kore</string>
|
||||
<string name="show_play_with_kodi_title">Show \"Play with Kodi\" option</string>
|
||||
<string name="enable_lock_screen_video_thumbnail_title">Lock screen video thumbnail</string>
|
||||
<string name="show_play_with_kodi_summary">Display an option to play a video via Kodi media center</string>
|
||||
<string name="enable_lock_screen_video_thumbnail_summary">A video thumbnail is shown on the lock screen when using the background player</string>
|
||||
<string name="enable_old_notifications_title">Enable old notifications</string>
|
||||
<string name="enable_old_notifications_summary">This enables the old \"Custom RemoteViews\" notifications. If disabled modern MediaStyle notifications will be used.</string>
|
||||
<string name="scale_to_square_image_in_notifications_title">Scale image to 1:1 aspect ratio</string>
|
||||
<string name="scale_to_square_image_in_notifications_summary">This will scale the notification image from 16:9 to 1:1 aspect ratio</string>
|
||||
<string name="default_notification_slot_0_title">Notification slot 0</string>
|
||||
<string name="default_notification_slot_1_title">Notification slot 1</string>
|
||||
<string name="default_notification_slot_2_title">Notification slot 2</string>
|
||||
<string name="default_notification_slot_3_title">Notification slot 3</string>
|
||||
<string name="default_notification_slot_4_title">Notification slot 4</string>
|
||||
<string name="settings_notifications_compact_view_title">Notification compact view</string>
|
||||
<string name="settings_notifications_compact_view_summary">Notification slots to show in compact view</string>
|
||||
<string name="play_audio">Audio</string>
|
||||
<string name="default_audio_format_title">Default audio format</string>
|
||||
<string name="default_video_format_title">Default video format</string>
|
||||
@ -129,6 +138,7 @@
|
||||
<string name="settings_category_other_title">Other</string>
|
||||
<string name="settings_category_debug_title">Debug</string>
|
||||
<string name="settings_category_updates_title">Updates</string>
|
||||
<string name="settings_category_notifications_title">Notifications</string>
|
||||
<string name="background_player_playing_toast">Playing in background</string>
|
||||
<string name="popup_playing_toast">Playing in popup mode</string>
|
||||
<string name="background_player_append">Queued on background player</string>
|
||||
|
@ -1,38 +1,110 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/settings_category_appearance_title">
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="@string/default_theme_value"
|
||||
android:entries="@array/theme_description_list"
|
||||
android:entryValues="@array/theme_values_list"
|
||||
android:key="@string/theme_key"
|
||||
android:summary="%s"
|
||||
android:title="@string/theme_title"/>
|
||||
android:title="@string/theme_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="true"
|
||||
android:key="@string/show_hold_to_append_key"
|
||||
android:summary="@string/show_hold_to_append_summary"
|
||||
android:title="@string/show_hold_to_append_title"
|
||||
android:summary="@string/show_hold_to_append_summary"/>
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="@string/list_view_mode_value"
|
||||
android:entries="@array/list_view_mode_description"
|
||||
android:entryValues="@array/list_view_mode_values"
|
||||
android:key="@string/list_view_mode_key"
|
||||
android:summary="%s"
|
||||
android:title="@string/list_view_mode"/>
|
||||
android:title="@string/list_view_mode"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:key="@string/caption_settings_key"
|
||||
android:summary="@string/caption_setting_description"
|
||||
android:title="@string/caption_setting_title"
|
||||
android:summary="@string/caption_setting_description"/>
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings_category_notifications_title"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/enable_old_notifications_key"
|
||||
android:summary="@string/enable_old_notifications_summary"
|
||||
android:title="@string/enable_old_notifications_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/scale_to_square_image_in_notifications_key"
|
||||
android:summary="@string/scale_to_square_image_in_notifications_summary"
|
||||
android:title="@string/scale_to_square_image_in_notifications_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="@string/notification_slot_0_value"
|
||||
android:entries="@array/notification_slot_0_description_list"
|
||||
android:entryValues="@array/notification_slot_0_values_list"
|
||||
android:key="@string/notification_slot_0_key"
|
||||
android:summary="%s"
|
||||
android:title="@string/default_notification_slot_0_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="@string/notification_slot_1_value"
|
||||
android:entries="@array/notification_slot_1_description_list"
|
||||
android:entryValues="@array/notification_slot_1_values_list"
|
||||
android:key="@string/notification_slot_1_key"
|
||||
android:summary="%s"
|
||||
android:title="@string/default_notification_slot_1_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="@string/notification_slot_2_value"
|
||||
android:entries="@array/notification_slot_2_description_list"
|
||||
android:entryValues="@array/notification_slot_2_values_list"
|
||||
android:key="@string/notification_slot_2_key"
|
||||
android:summary="%s"
|
||||
android:title="@string/default_notification_slot_2_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="@string/notification_slot_3_value"
|
||||
android:entries="@array/notification_slot_3_description_list"
|
||||
android:entryValues="@array/notification_slot_3_values_list"
|
||||
android:key="@string/notification_slot_3_key"
|
||||
android:summary="%s"
|
||||
android:title="@string/default_notification_slot_3_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="@string/notification_slot_4_value"
|
||||
android:entries="@array/notification_slot_4_description_list"
|
||||
android:entryValues="@array/notification_slot_4_values_list"
|
||||
android:key="@string/notification_slot_4_key"
|
||||
android:summary="%s"
|
||||
android:title="@string/default_notification_slot_4_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue="@string/settings_notifications_compact_view_default_value"
|
||||
android:key="@string/settings_notifications_compact_view_key"
|
||||
android:summary="@string/settings_notifications_compact_view_summary"
|
||||
android:title="@string/settings_notifications_compact_view_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
@ -81,13 +81,6 @@
|
||||
android:summary="@string/show_play_with_kodi_summary"
|
||||
android:title="@string/show_play_with_kodi_title"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="true"
|
||||
android:key="@string/enable_lock_screen_video_thumbnail_key"
|
||||
android:summary="@string/enable_lock_screen_video_thumbnail_summary"
|
||||
android:title="@string/enable_lock_screen_video_thumbnail_title"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
|