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 943d685b1..efbe2b912 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
@@ -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);
}
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/NotificationUtil.java b/app/src/main/java/org/schabi/newpipe/player/NotificationUtil.java
new file mode 100644
index 000000000..68648a8ad
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/player/NotificationUtil.java
@@ -0,0 +1,1379 @@
+package org.schabi.newpipe.player;
+
+import android.annotation.SuppressLint;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.os.Build;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import androidx.core.app.NotificationCompat;
+import androidx.core.content.ContextCompat;
+
+import com.google.android.exoplayer2.Player;
+
+import org.schabi.newpipe.BuildConfig;
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.util.NavigationHelper;
+
+import static android.content.Context.NOTIFICATION_SERVICE;
+import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
+
+/**
+ * This is a utility class for player notifications.
+ *
+ * @author cool-student
+ */
+public final class NotificationUtil {
+ private static final String TAG = "NotificationUtil";
+ private static final boolean DEBUG = BasePlayer.DEBUG;
+
+ public static final int NOTIFICATION_ID_BACKGROUND = 123789;
+ public static final int NOTIFICATION_ID_POPUP = 40028922;
+ static final int NOTIFICATION_UPDATES_BEFORE_RESET = 60; // only used for old notifications
+
+ static int timesNotificationUpdated; // only used for old notifications
+
+ NotificationCompat.Builder notificationBuilder;
+
+ String notificationSlot0 = "smart_rewind_prev";
+ String notificationSlot1 = "play_pause_buffering";
+ String notificationSlot2 = "smart_forward_next";
+ String notificationSlot3 = "repeat";
+ String notificationSlot4 = "close";
+
+ private NotificationManager notificationManager;
+ /*private NotificationManager notificationManager;
+ private NotificationCompat.Builder notificationBuilder;*/
+
+ private RemoteViews notificationPopupRemoteView;
+ private RemoteViews notificationRemoteView; // always null when new notifications are used
+ private RemoteViews bigNotificationRemoteView; // always null when new notifications are used
+
+ private int cachedDuration; // only used for old notifications
+ private String cachedDurationString; // only used for old notifications
+
+ private NotificationUtil() { }
+
+ public static NotificationUtil getInstance() {
+ return LazyHolder.INSTANCE;
+ }
+
+ void recreatePopupPlayerNotification(final Context context,
+ final MediaSessionCompat.Token mediaSessionCompatToken,
+ final PopupVideoPlayer.VideoPlayerImpl playerImpl,
+ final SharedPreferences sharedPreferences,
+ final boolean recreate) {
+ final boolean areOldNotificationsEnabled = sharedPreferences
+ .getBoolean(context.getString(R.string.enable_old_notifications_key), false);
+ if (areOldNotificationsEnabled) {
+ notificationBuilder = createOldPopupPlayerNotification(context, playerImpl);
+ } else if (notificationBuilder == null || recreate) {
+ Log.d(TAG, "N_ recreatePopupPlayerNotification(true)");
+ notificationBuilder = createPopupPlayerNotification(context, mediaSessionCompatToken,
+ playerImpl, sharedPreferences);
+ }
+ timesNotificationUpdated = 0;
+ }
+
+ void recreatePopupPlayerNotification(final Context context,
+ final MediaSessionCompat.Token mediaSessionCompatToken,
+ final PopupVideoPlayer.VideoPlayerImpl playerImpl,
+ final SharedPreferences sharedPreferences) {
+ final boolean areOldNotificationsEnabled = sharedPreferences
+ .getBoolean(context.getString(R.string.enable_old_notifications_key), false);
+ if (areOldNotificationsEnabled) {
+ notificationBuilder = createOldPopupPlayerNotification(context, playerImpl);
+ } else if (notificationBuilder == null) {
+ Log.d(TAG, "N_ recreatePopupPlayerNotification()");
+ notificationBuilder = createPopupPlayerNotification(context,
+ mediaSessionCompatToken, playerImpl, sharedPreferences);
+ }
+ timesNotificationUpdated = 0;
+ }
+
+ void recreateBackgroundPlayerNotification(
+ final Context context, final MediaSessionCompat.Token mediaSessionCompatToken,
+ final BackgroundPlayer.BasePlayerImpl basePlayerImpl,
+ final SharedPreferences sharedPreferences, final boolean recreate) {
+ final boolean areOldNotificationsEnabled = sharedPreferences
+ .getBoolean(context.getString(R.string.enable_old_notifications_key), false);
+ if (notificationBuilder == null || recreate || areOldNotificationsEnabled) {
+ Log.d(TAG, "N_ recreateBackgroundPlayerNotification(true)");
+ notificationBuilder = createBackgroundPlayerNotification(context,
+ mediaSessionCompatToken, basePlayerImpl, sharedPreferences);
+ }
+ timesNotificationUpdated = 0;
+ }
+
+ void recreateBackgroundPlayerNotification(
+ final Context context, final MediaSessionCompat.Token mediaSessionCompatToken,
+ final BackgroundPlayer.BasePlayerImpl basePlayerImpl,
+ final SharedPreferences sharedPreferences) {
+ final boolean areOldNotificationsEnabled = sharedPreferences
+ .getBoolean(context.getString(R.string.enable_old_notifications_key), false);
+ if (notificationBuilder == null || areOldNotificationsEnabled) {
+ Log.d(TAG, "N_ recreateBackgroundPlayerNotification()");
+ notificationBuilder = createBackgroundPlayerNotification(context,
+ mediaSessionCompatToken, basePlayerImpl, sharedPreferences);
+ }
+ timesNotificationUpdated = 0;
+ }
+
+ NotificationCompat.Builder createBackgroundPlayerNotification(
+ final Context context, final MediaSessionCompat.Token mediaSessionCompatToken,
+ final BackgroundPlayer.BasePlayerImpl basePlayerImpl,
+ final SharedPreferences sharedPreferences) {
+ notificationManager = ((NotificationManager) context
+ .getSystemService(NOTIFICATION_SERVICE));
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context,
+ context.getString(R.string.notification_channel_id));
+
+ final boolean areOldNotificationsEnabled = sharedPreferences
+ .getBoolean(context.getString(R.string.enable_old_notifications_key), false);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || areOldNotificationsEnabled) {
+ notificationRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
+ R.layout.player_background_notification);
+ bigNotificationRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
+ R.layout.player_background_notification_expanded);
+
+ setupOldNotification(notificationRemoteView, context, basePlayerImpl);
+ setupOldNotification(bigNotificationRemoteView, context, basePlayerImpl);
+
+ builder
+ .setOngoing(true)
+ .setSmallIcon(R.drawable.ic_newpipe_triangle_white)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setCustomContentView(notificationRemoteView)
+ .setCustomBigContentView(bigNotificationRemoteView)
+ .setPriority(NotificationCompat.PRIORITY_MAX);
+ } else {
+ String compactView = sharedPreferences.getString(context.getString(
+ R.string.settings_notifications_compact_view_key), "0,1,2");
+ int compactSlot0;
+ int compactSlot1;
+ int compactSlot2;
+ try {
+ String[] parts = compactView.split(",");
+ compactSlot0 = Integer.parseInt(parts[0]);
+ compactSlot1 = Integer.parseInt(parts[1]);
+ compactSlot2 = Integer.parseInt(parts[2]);
+ if (compactSlot0 > 4) {
+ compactSlot0 = 0;
+ }
+ if (compactSlot1 > 4) {
+ compactSlot1 = 1;
+ }
+ if (compactSlot2 > 4) {
+ compactSlot2 = 2;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ compactSlot0 = 0;
+ compactSlot1 = 1;
+ compactSlot2 = 2;
+ }
+
+ builder
+ .setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
+ .setMediaSession(mediaSessionCompatToken)
+ .setShowCancelButton(false)
+ .setShowActionsInCompactView(compactSlot0, compactSlot1, compactSlot2))
+ .setOngoing(false)
+ .setContentIntent(PendingIntent.getActivity(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(NavigationHelper.getBackgroundPlayerActivityIntent(context)),
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .setSmallIcon(R.drawable.ic_newpipe_triangle_white)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setContentTitle(basePlayerImpl.getVideoTitle())
+ .setContentText(basePlayerImpl.getUploaderName())
+ .setDeleteIntent(PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_CLOSE),
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .setColor(ContextCompat.getColor(context, R.color.gray))
+ .setPriority(NotificationCompat.PRIORITY_HIGH);
+ final boolean scaleImageToSquareAspectRatio = sharedPreferences.getBoolean(context
+ .getString(R.string.scale_to_square_image_in_notifications_key), false);
+ if (scaleImageToSquareAspectRatio) {
+ builder.setLargeIcon(getBitmapWithSquareAspectRatio(basePlayerImpl.getThumbnail()));
+ } else {
+ builder.setLargeIcon(basePlayerImpl.getThumbnail());
+ }
+
+ notificationSlot0 = sharedPreferences.getString(
+ context.getString(R.string.notification_slot_0_key), notificationSlot0);
+ notificationSlot1 = sharedPreferences.getString(
+ context.getString(R.string.notification_slot_1_key), notificationSlot1);
+ notificationSlot2 = sharedPreferences.getString(
+ context.getString(R.string.notification_slot_2_key), notificationSlot2);
+ notificationSlot3 = sharedPreferences.getString(
+ context.getString(R.string.notification_slot_3_key), notificationSlot3);
+ notificationSlot4 = sharedPreferences.getString(
+ context.getString(R.string.notification_slot_4_key), notificationSlot4);
+
+ addAction(context, builder, basePlayerImpl, notificationSlot0);
+ addAction(context, builder, basePlayerImpl, notificationSlot1);
+ addAction(context, builder, basePlayerImpl, notificationSlot2);
+ addAction(context, builder, basePlayerImpl, notificationSlot3);
+ addAction(context, builder, basePlayerImpl, notificationSlot4);
+ }
+
+ return builder;
+ }
+
+ private void addAction(final Context context, final NotificationCompat.Builder builder,
+ final BackgroundPlayer.BasePlayerImpl basePlayerImpl,
+ final String slot) {
+ switch (slot) {
+ case "play_pause_buffering":
+ if (basePlayerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
+ || basePlayerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
+ || basePlayerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
+ builder.addAction(R.drawable.ic_file_download_white_24dp, "Buffering",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_BUFFERING),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ builder.setSmallIcon(android.R.drawable.stat_sys_download);
+ } else {
+ builder.setSmallIcon(R.drawable.ic_newpipe_triangle_white);
+ if (basePlayerImpl.isPlaying()) {
+ builder.addAction(R.drawable.exo_notification_pause, "Pause",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_notification_play, "Play",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ }
+ break;
+ case "play_pause":
+ if (basePlayerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
+ || basePlayerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
+ || basePlayerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
+ builder.addAction(R.drawable.exo_notification_pause, "Pause",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else if (basePlayerImpl.isPlaying()) {
+ builder.addAction(R.drawable.exo_notification_pause, "Pause",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_notification_play, "Play",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ break;
+ case "rewind":
+ builder.addAction(R.drawable.exo_controls_rewind, "Rewind",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_REWIND),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case "smart_rewind_prev":
+ if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) {
+ builder.addAction(R.drawable.exo_notification_previous, "Prev",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PREVIOUS),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_controls_rewind, "Rewind",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_REWIND),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ break;
+ case "forward":
+ builder.addAction(R.drawable.exo_controls_fastforward, "Forward",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_FORWARD),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case "smart_forward_next":
+ if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) {
+ builder.addAction(R.drawable.exo_notification_next, "Next",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_NEXT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_controls_fastforward, "Forward",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_FORWARD),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ break;
+ case "next":
+ builder.addAction(R.drawable.exo_notification_next, "Next",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_NEXT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case "repeat":
+ switch (basePlayerImpl.getRepeatMode()) {
+ case Player.REPEAT_MODE_ONE:
+ builder.addAction(R.drawable.exo_controls_repeat_one, "RepeatOne",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case Player.REPEAT_MODE_ALL:
+ builder.addAction(R.drawable.exo_controls_repeat_all, "RepeatAll",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case Player.REPEAT_MODE_OFF:
+ default:
+ builder.addAction(R.drawable.exo_controls_repeat_off, "RepeatOff",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ }
+ break;
+ case "shuffle":
+ if (basePlayerImpl.playQueue.isShuffled()) {
+ builder.addAction(R.drawable.exo_controls_shuffle_on, "ShuffleOn",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_SHUFFLE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_controls_shuffle_off, "ShuffleOff",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_SHUFFLE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ break;
+ case "close":
+ builder.addAction(R.drawable.ic_close_white_32dp, "Close",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_CLOSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case "n/a":
+ // do nothing
+ break;
+ case "prev":
+ default:
+ builder.addAction(R.drawable.exo_notification_previous, "Prev",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PREVIOUS),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ }
+ }
+
+ /**
+ * Updates the notification, and the button icons depending on the playback state.
+ * On old notifications used for changes on the remoteView
+ *
+ * @param drawableId if != -1, sets the drawable with that id on the play/pause button
+ * @param context
+ * @param basePlayerImpl
+ * @param sharedPreferences
+ */
+ synchronized void updateBackgroundPlayerNotification(
+ final int drawableId, final Context context,
+ final BackgroundPlayer.BasePlayerImpl basePlayerImpl,
+ final SharedPreferences sharedPreferences) {
+ if (DEBUG) {
+ Log.d(TAG, "N_ updateBackgroundPlayerNotification()");
+ }
+
+ if (notificationBuilder == null) {
+ return;
+ }
+ if (drawableId != -1) {
+ if (notificationRemoteView != null) {
+ notificationRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
+ }
+ if (bigNotificationRemoteView != null) {
+ bigNotificationRemoteView
+ .setImageViewResource(R.id.notificationPlayPause, drawableId);
+ }
+ }
+
+ final boolean areOldNotificationsEnabled = sharedPreferences
+ .getBoolean(context.getString(R.string.enable_old_notifications_key), false);
+ if (!areOldNotificationsEnabled) {
+ notificationBuilder.setContentTitle(basePlayerImpl.getVideoTitle());
+ notificationBuilder.setContentText(basePlayerImpl.getUploaderName());
+ final boolean scaleImageToSquareAspectRatio = sharedPreferences.getBoolean(
+ context.getString(R.string.scale_to_square_image_in_notifications_key), false);
+ if (scaleImageToSquareAspectRatio) {
+ notificationBuilder.setLargeIcon(getBitmapWithSquareAspectRatio(basePlayerImpl
+ .getThumbnail()));
+ } else {
+ notificationBuilder.setLargeIcon(basePlayerImpl.getThumbnail());
+ }
+
+ setAction(context, basePlayerImpl, notificationSlot0, 0);
+ setAction(context, basePlayerImpl, notificationSlot1, 1);
+ setAction(context, basePlayerImpl, notificationSlot2, 2);
+ setAction(context, basePlayerImpl, notificationSlot3, 3);
+ setAction(context, basePlayerImpl, notificationSlot4, 4);
+ }
+
+ notificationManager.notify(NOTIFICATION_ID_BACKGROUND, notificationBuilder.build());
+
+ if (areOldNotificationsEnabled) {
+ timesNotificationUpdated++;
+ }
+ }
+
+ @SuppressLint("RestrictedApi")
+ private void setAction(final Context context,
+ final BackgroundPlayer.BasePlayerImpl basePlayerImpl,
+ final String slot, final int slotNumber) {
+ switch (slot) {
+ case "play_pause_buffering":
+ if (basePlayerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
+ || basePlayerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
+ || basePlayerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.ic_file_download_white_24dp,
+ "Buffering", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_BUFFERING),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ notificationBuilder.setSmallIcon(android.R.drawable.stat_sys_download);
+ } else if (basePlayerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.ic_replay_white_32dp,
+ "Completed", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.setSmallIcon(R.drawable.ic_newpipe_triangle_white);
+ if (basePlayerImpl.isPlaying()) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_pause,
+ "Pause", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_play,
+ "Play", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ }
+ break;
+ case "play_pause":
+ if (basePlayerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
+ || basePlayerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
+ || basePlayerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_pause,
+ "Pause", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else if (basePlayerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.ic_replay_white_32dp,
+ "Completed", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ if (basePlayerImpl.isPlaying()) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_pause,
+ "Pause", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_play,
+ "Play", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ }
+ break;
+ case "rewind":
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_rewind, "Rewind",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_REWIND),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case "smart_rewind_prev":
+ if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_previous,
+ "Prev", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PREVIOUS),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_rewind, "Rewind",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_REWIND),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ break;
+ case "forward":
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_fastforward,
+ "Forward", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_FORWARD),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case "smart_forward_next":
+ if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_next, "Next",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_NEXT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_fastforward,
+ "Forward", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_FORWARD),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ break;
+ case "next":
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_next, "Next",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_NEXT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case "repeat":
+ switch (basePlayerImpl.getRepeatMode()) {
+ case Player.REPEAT_MODE_ONE:
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_repeat_one,
+ "RepeatOne", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case Player.REPEAT_MODE_ALL:
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_repeat_all,
+ "RepeatAll", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case Player.REPEAT_MODE_OFF:
+ default:
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_repeat_off,
+ "RepeatOff", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ }
+ break;
+ case "shuffle":
+ if (basePlayerImpl.playQueue.isShuffled()) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_shuffle_on,
+ "ShuffleOn", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_SHUFFLE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_shuffle_off,
+ "ShuffleOff", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_SHUFFLE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ break;
+ case "close":
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.ic_close_white_32dp, "Close",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_CLOSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case "n/a":
+ // do nothing
+ break;
+ case "prev":
+ default:
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_previous, "Prev",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PREVIOUS),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ }
+ }
+
+ private NotificationCompat.Builder createPopupPlayerNotification(
+ final Context context, final MediaSessionCompat.Token mediaSessionCompatToken,
+ final PopupVideoPlayer.VideoPlayerImpl playerImpl,
+ final SharedPreferences sharedPreferences) {
+ notificationManager = ((NotificationManager) context
+ .getSystemService(NOTIFICATION_SERVICE));
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context,
+ context.getString(R.string.notification_channel_id));
+
+ String compactView = sharedPreferences.getString(context
+ .getString(R.string.settings_notifications_compact_view_key), "0,1,2");
+ int compactSlot0;
+ int compactSlot1;
+ int compactSlot2;
+ try {
+ String[] parts = compactView.split(",");
+ compactSlot0 = Integer.parseInt(parts[0]);
+ compactSlot1 = Integer.parseInt(parts[1]);
+ compactSlot2 = Integer.parseInt(parts[2]);
+ if (compactSlot0 > 4) {
+ compactSlot0 = 0;
+ }
+ if (compactSlot1 > 4) {
+ compactSlot1 = 1;
+ }
+ if (compactSlot2 > 4) {
+ compactSlot2 = 2;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ compactSlot0 = 0;
+ compactSlot1 = 1;
+ compactSlot2 = 2;
+ }
+
+ builder
+ .setStyle(
+ new androidx.media.app.NotificationCompat.MediaStyle()
+ .setMediaSession(mediaSessionCompatToken)
+ .setShowCancelButton(false)
+ .setShowActionsInCompactView(compactSlot0, compactSlot1,
+ compactSlot2))
+ .setOngoing(false)
+ .setContentIntent(PendingIntent.getActivity(context, NOTIFICATION_ID_POPUP,
+ new Intent(NavigationHelper.getPopupPlayerActivityIntent(context)),
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .setSmallIcon(R.drawable.ic_newpipe_triangle_white)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setContentTitle(playerImpl.getVideoTitle())
+ .setContentText(playerImpl.getUploaderName())
+ .setDeleteIntent(PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_CLOSE),
+ PendingIntent.FLAG_UPDATE_CURRENT))
+ .setColor(ContextCompat.getColor(context, R.color.gray));
+ boolean scaleImageToSquareAspectRatio = sharedPreferences.getBoolean(context
+ .getString(R.string.scale_to_square_image_in_notifications_key), false);
+ if (scaleImageToSquareAspectRatio) {
+ builder.setLargeIcon(getBitmapWithSquareAspectRatio(playerImpl.getThumbnail()));
+ } else {
+ builder.setLargeIcon(playerImpl.getThumbnail());
+ }
+ notificationSlot0 = sharedPreferences.getString(context
+ .getString(R.string.notification_slot_0_key), notificationSlot0);
+ notificationSlot1 = sharedPreferences.getString(context
+ .getString(R.string.notification_slot_1_key), notificationSlot1);
+ notificationSlot2 = sharedPreferences.getString(context.
+ getString(R.string.notification_slot_2_key), notificationSlot2);
+ notificationSlot3 = sharedPreferences.getString(context
+ .getString(R.string.notification_slot_3_key), notificationSlot3);
+ notificationSlot4 = sharedPreferences.getString(context
+ .getString(R.string.notification_slot_4_key), notificationSlot4);
+
+ addAction(context, builder, playerImpl, notificationSlot0);
+ addAction(context, builder, playerImpl, notificationSlot1);
+ addAction(context, builder, playerImpl, notificationSlot2);
+ addAction(context, builder, playerImpl, notificationSlot3);
+ addAction(context, builder, playerImpl, notificationSlot4);
+
+ builder.setPriority(NotificationCompat.PRIORITY_HIGH);
+ return builder;
+ }
+
+ private void addAction(final Context context, final NotificationCompat.Builder builder,
+ final PopupVideoPlayer.VideoPlayerImpl playerImpl, final String slot) {
+ switch (slot) {
+ case "play_pause_buffering":
+ if (playerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
+ || playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
+ || playerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
+ builder.addAction(R.drawable.ic_file_download_white_24dp, "Buffering",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_BUFFERING),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ builder.setSmallIcon(android.R.drawable.stat_sys_download);
+ } else {
+ builder.setSmallIcon(R.drawable.ic_newpipe_triangle_white);
+ if (playerImpl.isPlaying()) {
+ builder.addAction(R.drawable.exo_notification_pause, "Pause",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_notification_play, "Play",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ }
+ break;
+ case "play_pause":
+ if (playerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
+ || playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
+ || playerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
+ builder.addAction(R.drawable.exo_notification_pause, "Pause",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else if (playerImpl.isPlaying()) {
+ builder.addAction(R.drawable.exo_notification_pause, "Pause",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_notification_play, "Play",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ break;
+ case "rewind":
+ builder.addAction(R.drawable.exo_controls_rewind, "Rewind",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_FAST_REWIND),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case "smart_rewind_prev":
+ if (playerImpl.playQueue != null && playerImpl.playQueue.size() > 1) {
+ builder.addAction(R.drawable.exo_notification_previous, "Prev",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PREVIOUS),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_controls_rewind, "Rewind",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_FAST_REWIND),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ break;
+ case "forward":
+ builder.addAction(R.drawable.exo_controls_fastforward, "Forward",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_FAST_FORWARD),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case "smart_forward_next":
+ if (playerImpl.playQueue != null && playerImpl.playQueue.size() > 1) {
+ builder.addAction(R.drawable.exo_notification_next, "Next",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_NEXT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_controls_fastforward, "Forward",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_FAST_FORWARD),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ break;
+ case "next":
+ builder.addAction(R.drawable.exo_notification_next, "Next",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_NEXT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case "repeat":
+ switch (playerImpl.getRepeatMode()) {
+ case Player.REPEAT_MODE_ONE:
+ builder.addAction(R.drawable.exo_controls_repeat_one, "RepeatOne",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case Player.REPEAT_MODE_ALL:
+ builder.addAction(R.drawable.exo_controls_repeat_all, "RepeatAll",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case Player.REPEAT_MODE_OFF:
+ default:
+ builder.addAction(R.drawable.exo_controls_repeat_off, "RepeatOff",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ }
+ break;
+ case "shuffle":
+ if (playerImpl.playQueue.isShuffled()) {
+ builder.addAction(R.drawable.exo_controls_shuffle_on, "ShuffleOn",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_SHUFFLE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ builder.addAction(R.drawable.exo_controls_shuffle_off, "ShuffleOff",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_SHUFFLE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ break;
+ case "close":
+ builder.addAction(R.drawable.ic_close_white_32dp, "Close",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_CLOSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ case "n/a":
+ // do nothing
+ break;
+ case "prev":
+ default:
+ builder.addAction(R.drawable.exo_notification_previous, "Prev",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PREVIOUS),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ }
+ }
+
+ /**
+ * Updates the notification, and the button icons depending on the playback state.
+ * On old notifications used for changes on the remoteView
+ *
+ * @param drawableId if != -1, sets the drawable with that id on the play/pause button
+ * @param context
+ * @param playerImpl
+ * @param sharedPreferences
+ */
+ @SuppressLint("RestrictedApi")
+ synchronized void updatePopupPlayerNotification(
+ final int drawableId, final Context context,
+ final PopupVideoPlayer.VideoPlayerImpl playerImpl,
+ final SharedPreferences sharedPreferences) {
+ if (DEBUG) {
+ Log.d(TAG, "N_ updatePopupPlayerNotification()");
+ }
+
+ if (notificationBuilder == null) {
+ return;
+ }
+
+ boolean areOldNotificationsEnabled = sharedPreferences.getBoolean(context
+ .getString(R.string.enable_old_notifications_key), false);
+ if (areOldNotificationsEnabled) {
+ updateOldPopupPlayerNotification(drawableId);
+ } else {
+ notificationBuilder.setContentTitle(playerImpl.getVideoTitle());
+ notificationBuilder.setContentText(playerImpl.getUploaderName());
+ boolean scaleImageToSquareAspectRatio = sharedPreferences.getBoolean(context.
+ getString(R.string.scale_to_square_image_in_notifications_key), false);
+ if (scaleImageToSquareAspectRatio) {
+ notificationBuilder
+ .setLargeIcon(getBitmapWithSquareAspectRatio(playerImpl.getThumbnail()));
+ } else {
+ notificationBuilder.setLargeIcon(playerImpl.getThumbnail());
+ }
+
+ setAction(context, playerImpl, notificationSlot0, 0);
+ setAction(context, playerImpl, notificationSlot1, 1);
+ setAction(context, playerImpl, notificationSlot2, 2);
+ setAction(context, playerImpl, notificationSlot3, 3);
+ setAction(context, playerImpl, notificationSlot4, 4);
+ }
+
+ notificationManager.notify(NOTIFICATION_ID_POPUP, notificationBuilder.build());
+
+ if (areOldNotificationsEnabled) {
+ timesNotificationUpdated++;
+ }
+ }
+
+ @SuppressLint("RestrictedApi")
+ private void setAction(final Context context, final PopupVideoPlayer.VideoPlayerImpl playerImpl,
+ final String slot, final int slotNumber) {
+ switch (slot) {
+ case "play_pause_buffering":
+ if (playerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
+ || playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
+ || playerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.ic_file_download_white_24dp,
+ "Buffering", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_BUFFERING),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ notificationBuilder.setSmallIcon(android.R.drawable.stat_sys_download);
+ } else if (playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.ic_replay_white_32dp,
+ "Completed", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.setSmallIcon(R.drawable.ic_newpipe_triangle_white);
+ if (playerImpl.isPlaying()) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_pause,
+ "Pause", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_play,
+ "Play", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ }
+ break;
+ case "play_pause":
+ if (playerImpl.getCurrentState() == BasePlayer.STATE_PREFLIGHT
+ || playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED
+ || playerImpl.getCurrentState() == BasePlayer.STATE_BUFFERING) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_pause,
+ "Pause", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else if (playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.ic_replay_white_32dp,
+ "Completed", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ if (playerImpl.isPlaying()) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_pause,
+ "Pause", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_play,
+ "Play", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ }
+ break;
+ case "rewind":
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_rewind,
+ "Rewind", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_FAST_REWIND),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case "smart_rewind_prev":
+ if (playerImpl.playQueue != null && playerImpl.playQueue.size() > 1) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_previous,
+ "Prev", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PREVIOUS),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_rewind,
+ "Rewind", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_FAST_REWIND),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ break;
+ case "forward":
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_fastforward,
+ "Forward", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_FAST_FORWARD),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case "smart_forward_next":
+ if (playerImpl.playQueue != null && playerImpl.playQueue.size() > 1) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_next, "Next",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_NEXT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_fastforward,
+ "Forward", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_FAST_FORWARD),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ break;
+ case "next":
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_next, "Next",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_NEXT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case "repeat":
+ switch (playerImpl.getRepeatMode()) {
+ case Player.REPEAT_MODE_ONE:
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_repeat_one,
+ "RepeatOne", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case Player.REPEAT_MODE_ALL:
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_repeat_all,
+ "RepeatAll", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case Player.REPEAT_MODE_OFF:
+ default:
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_repeat_off,
+ "RepeatOff", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ }
+ break;
+ case "shuffle":
+ if (playerImpl.playQueue.isShuffled()) {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_shuffle_on,
+ "ShuffleOn", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_SHUFFLE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ } else {
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_controls_shuffle_off,
+ "ShuffleOff", PendingIntent.getBroadcast(context,
+ NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_SHUFFLE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ }
+ break;
+ case "close":
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.ic_close_white_32dp, "Close",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_CLOSE),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ case "n/a": // do nothing
+ /*try { //FIXME maybe do nothing here ?
+ notificationBuilder.mActions.remove(slotNumber);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ e.printStackTrace();
+ }*/
+ break;
+ case "prev":
+ default:
+ notificationBuilder.mActions.set(slotNumber,
+ new NotificationCompat.Action(R.drawable.exo_notification_previous, "Prev",
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PREVIOUS),
+ PendingIntent.FLAG_UPDATE_CURRENT)));
+ break;
+ }
+ }
+
+ private Bitmap getBitmapWithSquareAspectRatio(final Bitmap bitmap) {
+ return getResizedBitmap(bitmap, bitmap.getWidth(), bitmap.getWidth());
+ }
+
+ private Bitmap getResizedBitmap(final Bitmap bitmap, final int newWidth, final int newHeight) {
+ int width = bitmap.getWidth();
+ int height = bitmap.getHeight();
+ float scaleWidth = ((float) newWidth) / width;
+ float scaleHeight = ((float) newHeight) / height;
+ Matrix matrix = new Matrix();
+ matrix.postScale(scaleWidth, scaleHeight);
+ return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
+ }
+
+ @Deprecated // only used for old notifications
+ private void setupOldNotification(final RemoteViews remoteViews, final Context context,
+ final BackgroundPlayer.BasePlayerImpl basePlayerImpl) {
+ 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(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ remoteViews.setOnClickPendingIntent(R.id.notificationStop,
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_CLOSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ remoteViews.setOnClickPendingIntent(R.id.notificationRepeat,
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+
+ // Starts background player activity -- attempts to unlock lockscreen
+ final Intent intent = NavigationHelper.getBackgroundPlayerActivityIntent(context);
+ remoteViews.setOnClickPendingIntent(R.id.notificationContent,
+ PendingIntent.getActivity(context, NOTIFICATION_ID_BACKGROUND, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT));
+
+ if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) {
+ remoteViews.setInt(R.id.notificationFRewind,
+ BackgroundPlayer.SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_previous);
+ remoteViews.setInt(R.id.notificationFForward,
+ BackgroundPlayer.SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_next);
+ remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_PREVIOUS),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_PLAY_NEXT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ } else {
+ remoteViews.setInt(R.id.notificationFRewind,
+ BackgroundPlayer.SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_rewind);
+ remoteViews.setInt(R.id.notificationFForward,
+ BackgroundPlayer.SET_IMAGE_RESOURCE_METHOD,
+ R.drawable.exo_controls_fastforward);
+ remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_REWIND),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_BACKGROUND,
+ new Intent(BackgroundPlayer.ACTION_FAST_FORWARD),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+
+ setRepeatModeIcon(remoteViews, basePlayerImpl.getRepeatMode());
+ }
+
+ @Deprecated // only used for old notifications
+ private void setRepeatModeIcon(final RemoteViews remoteViews, final int repeatMode) {
+ switch (repeatMode) {
+ case Player.REPEAT_MODE_OFF:
+ remoteViews.setInt(R.id.notificationRepeat,
+ BackgroundPlayer.SET_IMAGE_RESOURCE_METHOD,
+ R.drawable.exo_controls_repeat_off);
+ break;
+ case Player.REPEAT_MODE_ONE:
+ remoteViews.setInt(R.id.notificationRepeat,
+ BackgroundPlayer.SET_IMAGE_RESOURCE_METHOD,
+ R.drawable.exo_controls_repeat_one);
+ break;
+ case Player.REPEAT_MODE_ALL:
+ remoteViews.setInt(R.id.notificationRepeat,
+ BackgroundPlayer.SET_IMAGE_RESOURCE_METHOD,
+ R.drawable.exo_controls_repeat_all);
+ break;
+ }
+ }
+
+ @Deprecated // only used for old notifications
+ public void updateOldNotificationsThumbnail(
+ final BackgroundPlayer.BasePlayerImpl basePlayerImpl) {
+ if (basePlayerImpl == null) {
+ return;
+ }
+ if (notificationRemoteView != null) {
+ notificationRemoteView.setImageViewBitmap(R.id.notificationCover,
+ basePlayerImpl.getThumbnail());
+ }
+ if (bigNotificationRemoteView != null) {
+ bigNotificationRemoteView.setImageViewBitmap(R.id.notificationCover,
+ basePlayerImpl.getThumbnail());
+ }
+ }
+
+ @Deprecated // only used for old notifications
+ public void setProgressbarOnOldNotifications(final int max, final int progress,
+ final boolean indeterminate) {
+ if (bigNotificationRemoteView != null) { //FIXME put in Util and turn into a method
+ bigNotificationRemoteView.setProgressBar(R.id.notificationProgressBar, max, progress,
+ indeterminate);
+ }
+ if (notificationRemoteView != null) {
+ notificationRemoteView.setProgressBar(R.id.notificationProgressBar, max, progress,
+ indeterminate);
+ }
+ }
+
+ @Deprecated // only used for old notifications
+ public void unsetImageInOldNotifications() {
+ if (notificationRemoteView != null) {
+ notificationRemoteView.setImageViewBitmap(R.id.notificationCover, null);
+ }
+ if (bigNotificationRemoteView != null) {
+ bigNotificationRemoteView.setImageViewBitmap(R.id.notificationCover, null);
+ }
+ }
+
+ @Deprecated // only used for old notifications
+ public void setCachedDuration(final int currentProgress, final int duration) {
+ if (bigNotificationRemoteView != null) {
+ if (cachedDuration != duration) {
+ cachedDuration = duration;
+ cachedDurationString = getTimeString(duration);
+ }
+ bigNotificationRemoteView.setTextViewText(R.id.notificationTime,
+ getTimeString(currentProgress) + " / " + cachedDurationString);
+ }
+ }
+
+ @Deprecated
+ private NotificationCompat.Builder createOldPopupPlayerNotification(
+ final Context context, final PopupVideoPlayer.VideoPlayerImpl playerImpl) {
+ notificationManager = ((NotificationManager) context
+ .getSystemService(NOTIFICATION_SERVICE));
+ notificationBuilder = new NotificationCompat.Builder(context,
+ context.getString(R.string.notification_channel_id));
+
+ notificationPopupRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
+ R.layout.player_popup_notification);
+
+ notificationPopupRemoteView.setTextViewText(R.id.notificationSongName,
+ playerImpl.getVideoTitle());
+ notificationPopupRemoteView.setTextViewText(R.id.notificationArtist,
+ playerImpl.getUploaderName());
+ notificationPopupRemoteView.setImageViewBitmap(R.id.notificationCover,
+ playerImpl.getThumbnail());
+
+ notificationPopupRemoteView.setOnClickPendingIntent(R.id.notificationPlayPause,
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_PLAY_PAUSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ notificationPopupRemoteView.setOnClickPendingIntent(R.id.notificationStop,
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_CLOSE),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ notificationPopupRemoteView.setOnClickPendingIntent(R.id.notificationRepeat,
+ PendingIntent.getBroadcast(context, NOTIFICATION_ID_POPUP,
+ new Intent(PopupVideoPlayer.ACTION_REPEAT),
+ PendingIntent.FLAG_UPDATE_CURRENT));
+
+ // Starts popup player activity -- attempts to unlock lockscreen
+ final Intent intent = NavigationHelper.getPopupPlayerActivityIntent(context);
+ notificationPopupRemoteView.setOnClickPendingIntent(R.id.notificationContent,
+ PendingIntent.getActivity(context, NOTIFICATION_ID_POPUP, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT));
+
+ setRepeatPopupModeRemote(notificationPopupRemoteView, playerImpl.getRepeatMode());
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context,
+ context.getString(R.string.notification_channel_id))
+ .setOngoing(true)
+ .setSmallIcon(R.drawable.ic_newpipe_triangle_white)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setContent(notificationPopupRemoteView);
+
+ 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
+ */
+ @Deprecated
+ private void updateOldPopupPlayerNotification(final int drawableId) {
+ if (DEBUG) {
+ Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
+ }
+ if (notificationBuilder == null || notificationPopupRemoteView == null) {
+ return;
+ }
+ if (drawableId != -1) {
+ notificationPopupRemoteView.setImageViewResource(R.id.notificationPlayPause,
+ drawableId);
+ }
+ notificationManager.notify(NOTIFICATION_ID_POPUP, notificationBuilder.build());
+ }
+
+ @Deprecated // only used for old notifications
+ protected void setRepeatPopupModeRemote(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;
+ }
+ }
+
+ @Deprecated // only used for old notifications
+ public void unsetImageInOldPopupNotifications() {
+ if (notificationRemoteView != null) {
+ notificationRemoteView.setImageViewBitmap(R.id.notificationCover, null);
+ }
+ }
+
+ public void cancelNotification(final int id) {
+ try {
+ if (notificationManager != null) {
+ notificationManager.cancel(id);
+ }
+ } catch (Exception e) {
+ Log.e("NotificationUtil", "Exception", e);
+ }
+ }
+
+ private static class LazyHolder {
+ private static final NotificationUtil INSTANCE = new NotificationUtil();
+ }
+
+}
diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
index 0ccec3067..a1ad139f6 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
@@ -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) {
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 e101e2185..d0939a914 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
@@ -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);
}
/**
diff --git a/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java
index a9531693c..c9367c4c9 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/AppearanceSettingsFragment.java
@@ -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);
diff --git a/app/src/main/res/drawable-hdpi/ic_close_white_32dp.png b/app/src/main/res/drawable-hdpi/ic_close_white_32dp.png
new file mode 100644
index 000000000..b7c7ffd0e
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_close_white_32dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_replay_white_32dp.png b/app/src/main/res/drawable-hdpi/ic_replay_white_32dp.png
new file mode 100644
index 000000000..ac1dd1a66
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_replay_white_32dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_close_white_32dp.png b/app/src/main/res/drawable-mdpi/ic_close_white_32dp.png
new file mode 100644
index 000000000..20b61eaee
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_close_white_32dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_replay_white_32dp.png b/app/src/main/res/drawable-mdpi/ic_replay_white_32dp.png
new file mode 100644
index 000000000..0a1d09cbf
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_replay_white_32dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_close_white_32dp.png b/app/src/main/res/drawable-xhdpi/ic_close_white_32dp.png
new file mode 100644
index 000000000..cc1334734
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_close_white_32dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_replay_white_32dp.png b/app/src/main/res/drawable-xhdpi/ic_replay_white_32dp.png
new file mode 100644
index 000000000..dfa434473
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_replay_white_32dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_close_white_32dp.png b/app/src/main/res/drawable-xxhdpi/ic_close_white_32dp.png
new file mode 100644
index 000000000..396419219
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_close_white_32dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_replay_white_32dp.png b/app/src/main/res/drawable-xxhdpi/ic_replay_white_32dp.png
new file mode 100644
index 000000000..1573fb111
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_replay_white_32dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_close_white_32dp.png b/app/src/main/res/drawable-xxxhdpi/ic_close_white_32dp.png
new file mode 100644
index 000000000..c56b1fcfc
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_close_white_32dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_replay_white_32dp.png b/app/src/main/res/drawable-xxxhdpi/ic_replay_white_32dp.png
new file mode 100644
index 000000000..b51ecf755
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_replay_white_32dp.png differ
diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml
index 946d586de..e5278e840 100644
--- a/app/src/main/res/values/settings_keys.xml
+++ b/app/src/main/res/values/settings_keys.xml
@@ -96,6 +96,113 @@
- 144p
+ enable_old_notifications
+ notifications_compact_view
+ 0,1,2
+ scale_to_square_image_in_notifications
+
+ prev
+ next
+ rewind
+ forward
+ smart_rewind_prev
+ smart_forward_next
+ play_pause_buffering
+ play_pause
+ repeat
+ shuffle
+ close
+ n/a
+
+ notification_slot_0_key
+ @string/notification_slot_smart_rewind_prev_key
+
+ - Rewind / Previous
+ - Previous
+ - Rewind
+
+
+ - @string/notification_slot_smart_rewind_prev_key
+ - @string/notification_slot_prev_key
+ - @string/notification_slot_rewind_key
+
+
+ notification_slot_1_key
+ @string/notification_slot_play_pause_buffering_key
+
+ - Play / Pause / Buffering
+ - Play / Pause
+ - Rewind
+
+
+ - @string/notification_slot_play_pause_buffering_key
+ - @string/notification_slot_play_pause_key
+ - @string/notification_slot_rewind_key
+
+
+
+ notification_slot_2_key
+ @string/notification_slot_smart_forward_next_key
+
+ - Forward / Next
+ - Forward
+ - Next
+ - Play / Pause / Buffering
+ - Play / Pause
+
+
+ - @string/notification_slot_smart_forward_next_key
+ - @string/notification_slot_forward_key
+ - @string/notification_slot_next_key
+ - @string/notification_slot_play_pause_buffering_key
+ - @string/notification_slot_play_pause_key
+
+
+ notification_slot_3_key
+ @string/notification_slot_repeat_key
+
+ - Repeat
+ - Shuffle
+ - Previous
+ - Forward
+ - Forward / Next
+ - Rewind
+ - Rewind / Previous
+ - Close
+ - N/A
+
+
+ - @string/notification_slot_repeat_key
+ - @string/notification_slot_shuffle_key
+ - @string/notification_slot_prev_key
+ - @string/notification_slot_forward_key
+ - @string/notification_slot_smart_forward_next_key
+ - @string/notification_slot_rewind_key
+ - @string/notification_slot_smart_rewind_prev_key
+ - @string/notification_slot_close_key
+ - @string/notification_slot_n_a_key
+
+
+ notification_slot_4_key
+ @string/notification_slot_close_key
+
+ - Close
+ - Repeat
+ - Shuffle
+ - Next
+ - Forward
+ - Forward / Next
+ - N/A
+
+
+ - @string/notification_slot_close_key
+ - @string/notification_slot_repeat_key
+ - @string/notification_slot_shuffle_key
+ - @string/notification_slot_next_key
+ - @string/notification_slot_forward_key
+ - @string/notification_slot_smart_forward_next_key
+ - @string/notification_slot_n_a_key
+
video_mp4
video_webm
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3625e67f4..1d1c67364 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -57,9 +57,18 @@
Install missing Kore app?
org.xbmc.kore
Show \"Play with Kodi\" option
- Lock screen video thumbnail
Display an option to play a video via Kodi media center
- A video thumbnail is shown on the lock screen when using the background player
+ Enable old notifications
+ This enables the old \"Custom RemoteViews\" notifications. If disabled modern MediaStyle notifications will be used.
+ Scale image to 1:1 aspect ratio
+ This will scale the notification image from 16:9 to 1:1 aspect ratio
+ Notification slot 0
+ Notification slot 1
+ Notification slot 2
+ Notification slot 3
+ Notification slot 4
+ Notification compact view
+ Notification slots to show in compact view
Audio
Default audio format
Default video format
@@ -129,6 +138,7 @@
Other
Debug
Updates
+ Notifications
Playing in background
Playing in popup mode
Queued on background player
diff --git a/app/src/main/res/xml/appearance_settings.xml b/app/src/main/res/xml/appearance_settings.xml
index 31be267af..a77663843 100644
--- a/app/src/main/res/xml/appearance_settings.xml
+++ b/app/src/main/res/xml/appearance_settings.xml
@@ -1,38 +1,110 @@
-
+ android:title="@string/theme_title"
+ app:iconSpaceReserved="false" />
+ app:iconSpaceReserved="false" />
+ android:title="@string/list_view_mode"
+ app:iconSpaceReserved="false" />
+ app:iconSpaceReserved="false" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml
index d1757919b..0ff43ce90 100644
--- a/app/src/main/res/xml/video_audio_settings.xml
+++ b/app/src/main/res/xml/video_audio_settings.xml
@@ -81,13 +81,6 @@
android:summary="@string/show_play_with_kodi_summary"
android:title="@string/show_play_with_kodi_title"/>
-
-