Merge remote-tracking branch 'newpipe/dev' into rebase
This commit is contained in:
commit
fac13fb8cb
69 changed files with 1878 additions and 827 deletions
|
|
@ -25,12 +25,17 @@ import android.app.Service;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
|
@ -48,6 +53,7 @@ import org.schabi.newpipe.player.helper.LockManager;
|
|||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||
import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
|
||||
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
||||
import org.schabi.newpipe.util.BitmapUtils;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
|
|
@ -75,6 +81,7 @@ public final class BackgroundPlayer extends Service {
|
|||
|
||||
private BasePlayerImpl basePlayerImpl;
|
||||
private LockManager lockManager;
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Service-Activity Binder
|
||||
|
|
@ -95,6 +102,9 @@ public final class BackgroundPlayer extends Service {
|
|||
|
||||
private boolean shouldUpdateOnProgress;
|
||||
|
||||
private static final int NOTIFICATION_UPDATES_BEFORE_RESET = 60;
|
||||
private int timesNotificationUpdated;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Service's LifeCycle
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
|
@ -104,6 +114,7 @@ public final class BackgroundPlayer extends Service {
|
|||
if (DEBUG) Log.d(TAG, "onCreate() called");
|
||||
notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
|
||||
lockManager = new LockManager(this);
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
|
||||
ThemeHelper.setTheme(this);
|
||||
basePlayerImpl = new BasePlayerImpl(this);
|
||||
|
|
@ -180,6 +191,7 @@ public final class BackgroundPlayer extends Service {
|
|||
|
||||
private void resetNotification() {
|
||||
notBuilder = createNotification();
|
||||
timesNotificationUpdated = 0;
|
||||
}
|
||||
|
||||
private NotificationCompat.Builder createNotification() {
|
||||
|
|
@ -195,12 +207,45 @@ public final class BackgroundPlayer extends Service {
|
|||
.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(NotificationCompat.Builder builder) {
|
||||
boolean isLockScreenThumbnailEnabled = sharedPreferences.getBoolean(
|
||||
getString(R.string.enable_lock_screen_video_thumbnail_key),
|
||||
true
|
||||
);
|
||||
|
||||
if (isLockScreenThumbnailEnabled) {
|
||||
basePlayerImpl.mediaSessionManager.setLockScreenArt(
|
||||
builder,
|
||||
getCenteredThumbnailBitmap()
|
||||
);
|
||||
} else {
|
||||
basePlayerImpl.mediaSessionManager.clearLockScreenArt(builder);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Bitmap getCenteredThumbnailBitmap() {
|
||||
int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
|
||||
int screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels;
|
||||
|
||||
return BitmapUtils.centerCrop(
|
||||
basePlayerImpl.getThumbnail(),
|
||||
screenWidth,
|
||||
screenHeight);
|
||||
}
|
||||
|
||||
private void setupNotification(RemoteViews remoteViews) {
|
||||
if (basePlayerImpl == null) return;
|
||||
|
||||
|
|
@ -248,10 +293,13 @@ public final class BackgroundPlayer extends Service {
|
|||
//if (DEBUG) Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
|
||||
if (notBuilder == null) return;
|
||||
if (drawableId != -1) {
|
||||
if (notRemoteView != null) notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
||||
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
||||
if (notRemoteView != null)
|
||||
notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
||||
if (bigNotRemoteView != null)
|
||||
bigNotRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
||||
}
|
||||
notificationManager.notify(NOTIFICATION_ID, notBuilder.build());
|
||||
timesNotificationUpdated++;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -275,7 +323,8 @@ public final class BackgroundPlayer extends Service {
|
|||
|
||||
protected class BasePlayerImpl extends BasePlayer {
|
||||
|
||||
@NonNull final private AudioPlaybackResolver resolver;
|
||||
@NonNull
|
||||
final private AudioPlaybackResolver resolver;
|
||||
private int cachedDuration;
|
||||
private String cachedDurationString;
|
||||
|
||||
|
|
@ -294,8 +343,10 @@ public final class BackgroundPlayer extends Service {
|
|||
super.handleIntent(intent);
|
||||
|
||||
resetNotification();
|
||||
if (bigNotRemoteView != null) bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
||||
if (notRemoteView != null) notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
||||
if (bigNotRemoteView != null)
|
||||
bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
||||
if (notRemoteView != null)
|
||||
notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
|
||||
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||
}
|
||||
|
||||
|
|
@ -330,6 +381,7 @@ public final class BackgroundPlayer extends Service {
|
|||
updateNotificationThumbnail();
|
||||
updateNotification(-1);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// States Implementation
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
|
@ -351,10 +403,15 @@ public final class BackgroundPlayer extends Service {
|
|||
updateProgress(currentProgress, duration, bufferPercent);
|
||||
|
||||
if (!shouldUpdateOnProgress) return;
|
||||
resetNotification();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /*Oreo*/) updateNotificationThumbnail();
|
||||
if (timesNotificationUpdated > NOTIFICATION_UPDATES_BEFORE_RESET) {
|
||||
resetNotification();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /*Oreo*/) {
|
||||
updateNotificationThumbnail();
|
||||
}
|
||||
}
|
||||
if (bigNotRemoteView != null) {
|
||||
if(cachedDuration != duration) {
|
||||
if (cachedDuration != duration) {
|
||||
cachedDuration = duration;
|
||||
cachedDurationString = getTimeString(duration);
|
||||
}
|
||||
|
|
@ -382,8 +439,10 @@ public final class BackgroundPlayer extends Service {
|
|||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
if (notRemoteView != null) notRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
||||
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
||||
if (notRemoteView != null)
|
||||
notRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
||||
if (bigNotRemoteView != null)
|
||||
bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -55,10 +55,7 @@ public final class BackgroundPlayerActivity extends ServicePlayerActivity {
|
|||
return true;
|
||||
}
|
||||
|
||||
this.player.setRecovery();
|
||||
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
|
||||
getApplicationContext().startService(getSwitchIntent(PopupVideoPlayer.class));
|
||||
return true;
|
||||
return switchTo(PopupVideoPlayer.class);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ public abstract class BasePlayer implements
|
|||
@NonNull
|
||||
public static final String RESUME_PLAYBACK = "resume_playback";
|
||||
@NonNull
|
||||
public static final String START_PAUSED = "start_paused";
|
||||
@NonNull
|
||||
public static final String SELECT_ON_APPEND = "select_on_append";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -304,7 +306,7 @@ public abstract class BasePlayer implements
|
|||
}
|
||||
// Good to go...
|
||||
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
|
||||
/*playOnInit=*/true);
|
||||
/*playOnInit=*/!intent.getBooleanExtra(START_PAUSED, false));
|
||||
}
|
||||
|
||||
protected void initPlayback(@NonNull final PlayQueue queue,
|
||||
|
|
@ -944,10 +946,10 @@ public abstract class BasePlayer implements
|
|||
public void onPlayPause() {
|
||||
if (DEBUG) Log.d(TAG, "onPlayPause() called");
|
||||
|
||||
if (!isPlaying()) {
|
||||
onPlay();
|
||||
} else {
|
||||
if (isPlaying()) {
|
||||
onPause();
|
||||
} else {
|
||||
onPlay();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import android.database.ContentObserver;
|
|||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
|
|
@ -78,6 +79,7 @@ import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
|||
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
|
||||
import org.schabi.newpipe.util.AnimationUtils;
|
||||
import org.schabi.newpipe.util.FireTvUtils;
|
||||
import org.schabi.newpipe.util.KoreUtil;
|
||||
import org.schabi.newpipe.util.ListHelper;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
|
|
@ -480,6 +482,7 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||
private boolean queueVisible;
|
||||
|
||||
private ImageButton moreOptionsButton;
|
||||
private ImageButton kodiButton;
|
||||
private ImageButton shareButton;
|
||||
private ImageButton toggleOrientationButton;
|
||||
private ImageButton switchPopupButton;
|
||||
|
|
@ -516,6 +519,7 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||
|
||||
this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton);
|
||||
this.secondaryControls = rootView.findViewById(R.id.secondaryControls);
|
||||
this.kodiButton = rootView.findViewById(R.id.kodi);
|
||||
this.shareButton = rootView.findViewById(R.id.share);
|
||||
this.toggleOrientationButton = rootView.findViewById(R.id.toggleOrientation);
|
||||
this.switchBackgroundButton = rootView.findViewById(R.id.switchBackground);
|
||||
|
|
@ -527,6 +531,9 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||
|
||||
titleTextView.setSelected(true);
|
||||
channelTextView.setSelected(true);
|
||||
boolean showKodiButton = PreferenceManager.getDefaultSharedPreferences(this.context).getBoolean(
|
||||
this.context.getString(R.string.show_play_with_kodi_key), false);
|
||||
kodiButton.setVisibility(showKodiButton ? View.VISIBLE : View.GONE);
|
||||
|
||||
getRootView().setKeepScreenOn(true);
|
||||
}
|
||||
|
|
@ -563,6 +570,7 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||
closeButton.setOnClickListener(this);
|
||||
|
||||
moreOptionsButton.setOnClickListener(this);
|
||||
kodiButton.setOnClickListener(this);
|
||||
shareButton.setOnClickListener(this);
|
||||
toggleOrientationButton.setOnClickListener(this);
|
||||
switchBackgroundButton.setOnClickListener(this);
|
||||
|
|
@ -633,6 +641,17 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||
finish();
|
||||
}
|
||||
|
||||
public void onKodiShare() {
|
||||
onPause();
|
||||
try {
|
||||
NavigationHelper.playWithKore(this.context, Uri.parse(
|
||||
playerImpl.getVideoUrl().replace("https", "http")));
|
||||
} catch (Exception e) {
|
||||
if (DEBUG) Log.i(TAG, "Failed to start kore", e);
|
||||
KoreUtil.showInstallKoreDialog(this.context);
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Player Overrides
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
|
@ -659,7 +678,8 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||
this.getPlaybackPitch(),
|
||||
this.getPlaybackSkipSilence(),
|
||||
this.getPlaybackQuality(),
|
||||
false
|
||||
false,
|
||||
!isPlaying()
|
||||
);
|
||||
context.startService(intent);
|
||||
|
||||
|
|
@ -682,7 +702,8 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||
this.getPlaybackPitch(),
|
||||
this.getPlaybackSkipSilence(),
|
||||
this.getPlaybackQuality(),
|
||||
false
|
||||
false,
|
||||
!isPlaying()
|
||||
);
|
||||
context.startService(intent);
|
||||
|
||||
|
|
@ -731,6 +752,8 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||
} else if (v.getId() == closeButton.getId()) {
|
||||
onPlaybackShutdown();
|
||||
return;
|
||||
} else if (v.getId() == kodiButton.getId()) {
|
||||
onKodiShare();
|
||||
}
|
||||
|
||||
if (getCurrentState() != STATE_COMPLETED) {
|
||||
|
|
|
|||
|
|
@ -567,7 +567,8 @@ public final class PopupVideoPlayer extends Service {
|
|||
this.getPlaybackPitch(),
|
||||
this.getPlaybackSkipSilence(),
|
||||
this.getPlaybackQuality(),
|
||||
false
|
||||
false,
|
||||
!isPlaying()
|
||||
);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
|
|
@ -1123,4 +1124,4 @@ public final class PopupVideoPlayer extends Service {
|
|||
return distanceFromCloseButton(popupMotionEvent) <= getClosingRadius();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,10 +48,7 @@ public final class PopupVideoPlayerActivity extends ServicePlayerActivity {
|
|||
@Override
|
||||
public boolean onPlayerOptionSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.action_switch_background) {
|
||||
this.player.setRecovery();
|
||||
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
|
||||
getApplicationContext().startService(getSwitchIntent(BackgroundPlayer.class));
|
||||
return true;
|
||||
return switchTo(BackgroundPlayer.class);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,18 +157,11 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||
case R.id.action_append_playlist:
|
||||
appendAllToPlaylist();
|
||||
return true;
|
||||
case R.id.action_settings:
|
||||
NavigationHelper.openSettings(this);
|
||||
redraw = true;
|
||||
return true;
|
||||
case R.id.action_system_audio:
|
||||
startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS));
|
||||
return true;
|
||||
case R.id.action_switch_main:
|
||||
this.player.setRecovery();
|
||||
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
|
||||
getApplicationContext().startActivity(getSwitchIntent(MainVideoPlayer.class));
|
||||
return true;
|
||||
return switchTo(MainVideoPlayer.class);
|
||||
}
|
||||
return onPlayerOptionSelected(item) || super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
|
@ -189,8 +182,17 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||
this.player.getPlaybackPitch(),
|
||||
this.player.getPlaybackSkipSilence(),
|
||||
null,
|
||||
false,
|
||||
false
|
||||
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.putExtra(BasePlayer.START_PAUSED, !this.player.isPlaying());
|
||||
}
|
||||
|
||||
protected boolean switchTo(final Class clazz) {
|
||||
this.player.setRecovery();
|
||||
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
|
||||
getApplicationContext().startActivity(getSwitchIntent(clazz));
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -2,12 +2,19 @@ package org.schabi.newpipe.player.helper;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.MediaMetadata;
|
||||
import android.os.Build;
|
||||
import android.support.v4.media.MediaMetadataCompat;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.media.session.MediaButtonReceiver;
|
||||
import androidx.media.app.NotificationCompat.MediaStyle;
|
||||
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
|
||||
|
|
@ -19,8 +26,10 @@ import org.schabi.newpipe.player.mediasession.PlayQueuePlaybackController;
|
|||
public class MediaSessionManager {
|
||||
private static final String TAG = "MediaSessionManager";
|
||||
|
||||
@NonNull private final MediaSessionCompat mediaSession;
|
||||
@NonNull private final MediaSessionConnector sessionConnector;
|
||||
@NonNull
|
||||
private final MediaSessionCompat mediaSession;
|
||||
@NonNull
|
||||
private final MediaSessionConnector sessionConnector;
|
||||
|
||||
public MediaSessionManager(@NonNull final Context context,
|
||||
@NonNull final Player player,
|
||||
|
|
@ -40,13 +49,45 @@ public class MediaSessionManager {
|
|||
return MediaButtonReceiver.handleIntent(mediaSession, intent);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public void setLockScreenArt(NotificationCompat.Builder builder, @Nullable Bitmap thumbnailBitmap) {
|
||||
if (thumbnailBitmap == null || !mediaSession.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mediaSession.setMetadata(
|
||||
new MediaMetadataCompat.Builder()
|
||||
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, thumbnailBitmap)
|
||||
.build()
|
||||
);
|
||||
|
||||
MediaStyle mediaStyle = new MediaStyle()
|
||||
.setMediaSession(mediaSession.getSessionToken());
|
||||
|
||||
builder.setStyle(mediaStyle);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public void clearLockScreenArt(NotificationCompat.Builder builder) {
|
||||
mediaSession.setMetadata(
|
||||
new MediaMetadataCompat.Builder()
|
||||
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, null)
|
||||
.build()
|
||||
);
|
||||
|
||||
MediaStyle mediaStyle = new MediaStyle()
|
||||
.setMediaSession(mediaSession.getSessionToken());
|
||||
|
||||
builder.setStyle(mediaStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called on player destruction to prevent leakage.
|
||||
* */
|
||||
*/
|
||||
public void dispose() {
|
||||
this.sessionConnector.setPlayer(null);
|
||||
this.sessionConnector.setQueueNavigator(null);
|
||||
this.mediaSession.setActive(false);
|
||||
this.mediaSession.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue