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