Merge remote-tracking branch 'newpipe/dev' into rebase

This commit is contained in:
Alexander-- 2020-01-29 03:10:16 +06:59
commit fac13fb8cb
69 changed files with 1878 additions and 827 deletions

View file

@ -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);
}
/*//////////////////////////////////////////////////////////////////////////

View file

@ -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;
}

View file

@ -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();
}
}

View file

@ -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) {

View file

@ -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();
}
}
}
}

View file

@ -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;
}

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////

View file

@ -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();
}
}
}