-Fixed memory leak due to permanent remote view bitmap references.
-Removed redundant code in popup player.
This commit is contained in:
parent
eb15c04254
commit
150c3b413a
|
@ -146,7 +146,7 @@ public class BackgroundPlayer extends Service {
|
||||||
private void onScreenOnOff(boolean on) {
|
private void onScreenOnOff(boolean on) {
|
||||||
if (DEBUG) Log.d(TAG, "onScreenOnOff() called with: on = [" + on + "]");
|
if (DEBUG) Log.d(TAG, "onScreenOnOff() called with: on = [" + on + "]");
|
||||||
if (on) {
|
if (on) {
|
||||||
if (basePlayerImpl.isPlaying() && !basePlayerImpl.isProgressLoopRunning.get()) basePlayerImpl.startProgressLoop();
|
if (basePlayerImpl.isPlaying() && !basePlayerImpl.isProgressLoopRunning()) basePlayerImpl.startProgressLoop();
|
||||||
} else basePlayerImpl.stopProgressLoop();
|
} else basePlayerImpl.stopProgressLoop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ public class BackgroundPlayer extends Service {
|
||||||
*
|
*
|
||||||
* @param drawableId if != -1, sets the drawable with that id on the play/pause button
|
* @param drawableId if != -1, sets the drawable with that id on the play/pause button
|
||||||
*/
|
*/
|
||||||
private void updateNotification(int drawableId) {
|
private synchronized void updateNotification(int drawableId) {
|
||||||
if (DEBUG) Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
|
if (DEBUG) Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
|
||||||
if (notBuilder == null) return;
|
if (notBuilder == null) return;
|
||||||
if (drawableId != -1) {
|
if (drawableId != -1) {
|
||||||
|
@ -275,19 +275,27 @@ public class BackgroundPlayer extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initThumbnail() {
|
public void initThumbnail(final String url) {
|
||||||
if (notRemoteView != null) notRemoteView.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
|
if (notRemoteView != null) notRemoteView.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
|
||||||
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
|
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
|
||||||
updateNotification(-1);
|
updateNotification(-1);
|
||||||
super.initThumbnail();
|
super.initThumbnail(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onThumbnailReceived(Bitmap thumbnail) {
|
public void onThumbnailReceived(Bitmap thumbnail) {
|
||||||
super.onThumbnailReceived(thumbnail);
|
super.onThumbnailReceived(thumbnail);
|
||||||
|
|
||||||
if (thumbnail != null) {
|
if (thumbnail != null) {
|
||||||
if (notRemoteView != null) notRemoteView.setImageViewBitmap(R.id.notificationCover, thumbnail);
|
videoThumbnail = thumbnail;
|
||||||
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, thumbnail);
|
|
||||||
|
// rebuild notification here since remote view does not release bitmaps, causing memory leaks
|
||||||
|
// remove this line to see for yourself
|
||||||
|
notBuilder = createNotification();
|
||||||
|
|
||||||
|
if (notRemoteView != null) notRemoteView.setImageViewBitmap(R.id.notificationCover, videoThumbnail);
|
||||||
|
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, videoThumbnail);
|
||||||
|
|
||||||
updateNotification(-1);
|
updateNotification(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,7 +311,7 @@ public class BackgroundPlayer extends Service {
|
||||||
FAST_FORWARD_REWIND_AMOUNT = 10000;
|
FAST_FORWARD_REWIND_AMOUNT = 10000;
|
||||||
}
|
}
|
||||||
PROGRESS_LOOP_INTERVAL = 1000;
|
PROGRESS_LOOP_INTERVAL = 1000;
|
||||||
basePlayerImpl.getPlayer().setVolume(1f);
|
simpleExoPlayer.setVolume(1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -382,13 +390,13 @@ public class BackgroundPlayer extends Service {
|
||||||
public void sync(final StreamInfo info, final int sortedStreamsIndex) {
|
public void sync(final StreamInfo info, final int sortedStreamsIndex) {
|
||||||
super.sync(info, sortedStreamsIndex);
|
super.sync(info, sortedStreamsIndex);
|
||||||
|
|
||||||
basePlayerImpl.setVideoTitle(info.name);
|
setVideoTitle(info.name);
|
||||||
basePlayerImpl.setUploaderName(info.uploader_name);
|
setUploaderName(info.uploader_name);
|
||||||
|
|
||||||
notRemoteView.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
|
notRemoteView.setTextViewText(R.id.notificationSongName, getVideoTitle());
|
||||||
notRemoteView.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName());
|
notRemoteView.setTextViewText(R.id.notificationArtist, getUploaderName());
|
||||||
bigNotRemoteView.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
|
bigNotRemoteView.setTextViewText(R.id.notificationSongName, getVideoTitle());
|
||||||
bigNotRemoteView.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName());
|
bigNotRemoteView.setTextViewText(R.id.notificationArtist, getUploaderName());
|
||||||
updateNotification(-1);
|
updateNotification(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,7 +444,7 @@ public class BackgroundPlayer extends Service {
|
||||||
onVideoPlayPause();
|
onVideoPlayPause();
|
||||||
break;
|
break;
|
||||||
case ACTION_OPEN_DETAIL:
|
case ACTION_OPEN_DETAIL:
|
||||||
onOpenDetail(BackgroundPlayer.this, basePlayerImpl.getVideoUrl(), basePlayerImpl.getVideoTitle());
|
onOpenDetail(BackgroundPlayer.this, getVideoUrl(), getVideoTitle());
|
||||||
break;
|
break;
|
||||||
case ACTION_REPEAT:
|
case ACTION_REPEAT:
|
||||||
onRepeatClicked();
|
onRepeatClicked();
|
||||||
|
@ -483,7 +491,7 @@ public class BackgroundPlayer extends Service {
|
||||||
super.onPaused();
|
super.onPaused();
|
||||||
|
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
updateNotification(R.drawable.ic_play_arrow_white);
|
||||||
if (isProgressLoopRunning.get()) stopProgressLoop();
|
if (isProgressLoopRunning()) stopProgressLoop();
|
||||||
|
|
||||||
releaseWifiAndCpu();
|
releaseWifiAndCpu();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,9 @@ import android.content.SharedPreferences;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||||
|
@ -67,15 +64,14 @@ import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvicto
|
||||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.Downloader;
|
import org.schabi.newpipe.Downloader;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.player.playback.PlaybackManager;
|
|
||||||
import org.schabi.newpipe.player.playback.PlaybackListener;
|
import org.schabi.newpipe.player.playback.PlaybackListener;
|
||||||
|
import org.schabi.newpipe.player.playback.PlaybackManager;
|
||||||
import org.schabi.newpipe.playlist.ExternalPlayQueue;
|
import org.schabi.newpipe.playlist.ExternalPlayQueue;
|
||||||
import org.schabi.newpipe.playlist.PlayQueue;
|
import org.schabi.newpipe.playlist.PlayQueue;
|
||||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||||
|
@ -89,7 +85,19 @@ import java.util.ArrayList;
|
||||||
import java.util.Formatter;
|
import java.util.Formatter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.Single;
|
||||||
|
import io.reactivex.SingleObserver;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.annotations.NonNull;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
|
import io.reactivex.disposables.SerialDisposable;
|
||||||
|
import io.reactivex.functions.Consumer;
|
||||||
|
import io.reactivex.functions.Predicate;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base for the players, joining the common properties
|
* Base for the players, joining the common properties
|
||||||
|
@ -101,7 +109,7 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
AudioManager.OnAudioFocusChangeListener, PlaybackListener {
|
AudioManager.OnAudioFocusChangeListener, PlaybackListener {
|
||||||
// TODO: Check api version for deprecated audio manager methods
|
// TODO: Check api version for deprecated audio manager methods
|
||||||
|
|
||||||
public static final boolean DEBUG = false;
|
public static final boolean DEBUG = true;
|
||||||
public static final String TAG = "BasePlayer";
|
public static final String TAG = "BasePlayer";
|
||||||
|
|
||||||
protected Context context;
|
protected Context context;
|
||||||
|
@ -134,7 +142,6 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
protected String videoUrl = "";
|
protected String videoUrl = "";
|
||||||
protected String videoTitle = "";
|
protected String videoTitle = "";
|
||||||
protected String videoThumbnailUrl = "";
|
protected String videoThumbnailUrl = "";
|
||||||
protected long videoStartPos = -1;
|
|
||||||
protected String uploaderName = "";
|
protected String uploaderName = "";
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -144,8 +151,8 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
protected PlaybackManager playbackManager;
|
protected PlaybackManager playbackManager;
|
||||||
protected PlayQueue playQueue;
|
protected PlayQueue playQueue;
|
||||||
|
|
||||||
protected int restoreQueueIndex;
|
protected int queueStartPos = 0;
|
||||||
protected long restoreWindowPos;
|
protected long videoStartPos = -1;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Player
|
// Player
|
||||||
|
@ -157,21 +164,19 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
protected SimpleExoPlayer simpleExoPlayer;
|
protected SimpleExoPlayer simpleExoPlayer;
|
||||||
protected boolean isPrepared = false;
|
protected boolean isPrepared = false;
|
||||||
|
|
||||||
protected MediaSource mediaSource;
|
|
||||||
protected CacheDataSourceFactory cacheDataSourceFactory;
|
protected CacheDataSourceFactory cacheDataSourceFactory;
|
||||||
protected final DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
|
protected final DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
|
||||||
protected final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
protected final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||||
|
|
||||||
protected int PROGRESS_LOOP_INTERVAL = 100;
|
protected int PROGRESS_LOOP_INTERVAL = 100;
|
||||||
protected AtomicBoolean isProgressLoopRunning = new AtomicBoolean();
|
protected Disposable progressUpdateReactor;
|
||||||
protected Handler progressLoop;
|
|
||||||
protected Runnable progressUpdate;
|
protected SerialDisposable thumbnailReactor;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public BasePlayer(Context context) {
|
public BasePlayer(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.progressLoop = new Handler();
|
|
||||||
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
this.audioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE));
|
this.audioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE));
|
||||||
|
|
||||||
|
@ -184,6 +189,8 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
this.intentFilter = new IntentFilter();
|
this.intentFilter = new IntentFilter();
|
||||||
setupBroadcastReceiver(intentFilter);
|
setupBroadcastReceiver(intentFilter);
|
||||||
context.registerReceiver(broadcastReceiver, intentFilter);
|
context.registerReceiver(broadcastReceiver, intentFilter);
|
||||||
|
|
||||||
|
this.thumbnailReactor = new SerialDisposable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
@ -223,23 +230,31 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
simpleExoPlayer.addListener(this);
|
simpleExoPlayer.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initListeners() {
|
public void initListeners() {}
|
||||||
progressUpdate = new Runnable() {
|
|
||||||
|
protected Disposable getProgressReactor() {
|
||||||
|
return Observable.interval(PROGRESS_LOOP_INTERVAL, TimeUnit.MILLISECONDS)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.filter(new Predicate<Long>() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public boolean test(@NonNull Long aLong) throws Exception {
|
||||||
//if(DEBUG) Log.d(TAG, "progressUpdate run() called");
|
return isProgressLoopRunning();
|
||||||
onUpdateProgress((int) simpleExoPlayer.getCurrentPosition(), (int) simpleExoPlayer.getDuration(), simpleExoPlayer.getBufferedPercentage());
|
|
||||||
if (isProgressLoopRunning.get()) progressLoop.postDelayed(this, PROGRESS_LOOP_INTERVAL);
|
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
.subscribe(new Consumer<Long>() {
|
||||||
|
@Override
|
||||||
|
public void accept(Long aLong) throws Exception {
|
||||||
|
triggerProgressUpdate();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleIntent(Intent intent) {
|
public void handleIntent(Intent intent) {
|
||||||
if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]");
|
if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]");
|
||||||
if (intent == null) return;
|
if (intent == null) return;
|
||||||
|
|
||||||
restoreQueueIndex = intent.getIntExtra(RESTORE_QUEUE_INDEX, 0);
|
queueStartPos = intent.getIntExtra(RESTORE_QUEUE_INDEX, 0);
|
||||||
restoreWindowPos = intent.getLongExtra(START_POSITION, 0);
|
videoStartPos = intent.getLongExtra(START_POSITION, 0);
|
||||||
setPlaybackSpeed(intent.getFloatExtra(PLAYBACK_SPEED, getPlaybackSpeed()));
|
setPlaybackSpeed(intent.getFloatExtra(PLAYBACK_SPEED, getPlaybackSpeed()));
|
||||||
|
|
||||||
switch (intent.getStringExtra(INTENT_TYPE)) {
|
switch (intent.getStringExtra(INTENT_TYPE)) {
|
||||||
|
@ -254,7 +269,6 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void handleExternalPlaylistIntent(Intent intent) {
|
public void handleExternalPlaylistIntent(Intent intent) {
|
||||||
final int serviceId = intent.getIntExtra(ExternalPlayQueue.SERVICE_ID, -1);
|
final int serviceId = intent.getIntExtra(ExternalPlayQueue.SERVICE_ID, -1);
|
||||||
|
@ -286,30 +300,46 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
playbackManager = new PlaybackManager(this, playQueue);
|
playbackManager = new PlaybackManager(this, playQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initThumbnail() {
|
public void initThumbnail(final String url) {
|
||||||
if (DEBUG) Log.d(TAG, "initThumbnail() called");
|
final Callable<Bitmap> bitmapCallable = new Callable<Bitmap>() {
|
||||||
videoThumbnail = null;
|
|
||||||
if (videoThumbnailUrl == null || videoThumbnailUrl.isEmpty()) return;
|
|
||||||
ImageLoader.getInstance().resume();
|
|
||||||
ImageLoader.getInstance().loadImage(videoThumbnailUrl, new SimpleImageLoadingListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
public Bitmap call() throws Exception {
|
||||||
if (simpleExoPlayer == null) return;
|
return ImageLoader.getInstance().loadImageSync(url);
|
||||||
if (DEBUG)
|
}
|
||||||
Log.d(TAG, "onLoadingComplete() called with: imageUri = [" + imageUri + "], view = [" + view + "], loadedImage = [" + loadedImage + "]");
|
};
|
||||||
videoThumbnail = loadedImage;
|
|
||||||
onThumbnailReceived(loadedImage);
|
Single.fromCallable(bitmapCallable)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(new SingleObserver<Bitmap>() {
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(@NonNull Disposable d) {
|
||||||
|
thumbnailReactor.set(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(@NonNull Bitmap bitmap) {
|
||||||
|
onThumbnailReceived(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(@NonNull Throwable e) {
|
||||||
|
Log.e(TAG, "Thumbnail Fetch Failed.", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onThumbnailReceived(Bitmap thumbnail) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onThumbnailReceived() called with: thumbnail = [" + thumbnail + "]");
|
||||||
|
}
|
||||||
|
|
||||||
public void destroyPlayer() {
|
public void destroyPlayer() {
|
||||||
if (DEBUG) Log.d(TAG, "destroyPlayer() called");
|
if (DEBUG) Log.d(TAG, "destroyPlayer() called");
|
||||||
if (simpleExoPlayer != null) {
|
if (simpleExoPlayer != null) {
|
||||||
simpleExoPlayer.stop();
|
simpleExoPlayer.stop();
|
||||||
simpleExoPlayer.release();
|
simpleExoPlayer.release();
|
||||||
}
|
}
|
||||||
if (progressLoop != null && isProgressLoopRunning.get()) stopProgressLoop();
|
if (isProgressLoopRunning()) stopProgressLoop();
|
||||||
if (audioManager != null) {
|
if (audioManager != null) {
|
||||||
audioManager.abandonAudioFocus(this);
|
audioManager.abandonAudioFocus(this);
|
||||||
audioManager = null;
|
audioManager = null;
|
||||||
|
@ -320,7 +350,11 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
if (DEBUG) Log.d(TAG, "destroy() called");
|
if (DEBUG) Log.d(TAG, "destroy() called");
|
||||||
destroyPlayer();
|
destroyPlayer();
|
||||||
unregisterBroadcastReceiver();
|
unregisterBroadcastReceiver();
|
||||||
|
|
||||||
|
thumbnailReactor.dispose();
|
||||||
|
thumbnailReactor = null;
|
||||||
videoThumbnail = null;
|
videoThumbnail = null;
|
||||||
|
|
||||||
simpleExoPlayer = null;
|
simpleExoPlayer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,19 +503,19 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
|
|
||||||
public void onLoading() {
|
public void onLoading() {
|
||||||
if (DEBUG) Log.d(TAG, "onLoading() called");
|
if (DEBUG) Log.d(TAG, "onLoading() called");
|
||||||
if (!isProgressLoopRunning.get()) startProgressLoop();
|
if (!isProgressLoopRunning()) startProgressLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPlaying() {
|
public void onPlaying() {
|
||||||
if (DEBUG) Log.d(TAG, "onPlaying() called");
|
if (DEBUG) Log.d(TAG, "onPlaying() called");
|
||||||
if (!isProgressLoopRunning.get()) startProgressLoop();
|
if (!isProgressLoopRunning()) startProgressLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBuffering() {
|
public void onBuffering() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPaused() {
|
public void onPaused() {
|
||||||
if (isProgressLoopRunning.get()) stopProgressLoop();
|
if (isProgressLoopRunning()) stopProgressLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPausedSeek() {
|
public void onPausedSeek() {
|
||||||
|
@ -489,7 +523,7 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
|
|
||||||
public void onCompleted() {
|
public void onCompleted() {
|
||||||
if (DEBUG) Log.d(TAG, "onCompleted() called");
|
if (DEBUG) Log.d(TAG, "onCompleted() called");
|
||||||
if (isProgressLoopRunning.get()) stopProgressLoop();
|
if (isProgressLoopRunning()) stopProgressLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -524,22 +558,25 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onTimelineChanged(), timeline size = " + timeline.getWindowCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||||
|
Log.w(TAG, "onTracksChanged() called, unsupported operation. Is this expected?");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
|
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
|
||||||
|
if (DEBUG) Log.d(TAG, "playbackParameters(), speed: " + playbackParameters.speed + ", pitch: " + playbackParameters.pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadingChanged(boolean isLoading) {
|
public void onLoadingChanged(boolean isLoading) {
|
||||||
if (DEBUG) Log.d(TAG, "onLoadingChanged() called with: isLoading = [" + isLoading + "]");
|
if (DEBUG) Log.d(TAG, "onLoadingChanged() called with: isLoading = [" + isLoading + "]");
|
||||||
|
|
||||||
if (!isLoading && getCurrentState() == STATE_PAUSED && isProgressLoopRunning.get()) stopProgressLoop();
|
if (!isLoading && getCurrentState() == STATE_PAUSED && isProgressLoopRunning()) stopProgressLoop();
|
||||||
else if (isLoading && !isProgressLoopRunning.get()) startProgressLoop();
|
else if (isLoading && !isProgressLoopRunning()) startProgressLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -595,6 +632,11 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
playbackManager.refresh(newIndex);
|
playbackManager.refresh(newIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRepeatModeChanged(int i) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onRepeatModeChanged() called with: mode = [" + i + "]");
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Playback Listener
|
// Playback Listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -614,13 +656,13 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
if (simpleExoPlayer == null) return;
|
if (simpleExoPlayer == null) return;
|
||||||
if (DEBUG) Log.d(TAG, "Unblocking...");
|
if (DEBUG) Log.d(TAG, "Unblocking...");
|
||||||
|
|
||||||
if (restoreQueueIndex != playQueue.getIndex()) {
|
if (queueStartPos != playQueue.getIndex()) {
|
||||||
restoreQueueIndex = playQueue.getIndex();
|
queueStartPos = playQueue.getIndex();
|
||||||
restoreWindowPos = 0;
|
videoStartPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
simpleExoPlayer.prepare(playbackManager.getMediaSource());
|
simpleExoPlayer.prepare(playbackManager.getMediaSource());
|
||||||
simpleExoPlayer.seekTo(playbackManager.getCurrentSourceIndex(), restoreWindowPos);
|
simpleExoPlayer.seekTo(playbackManager.getCurrentSourceIndex(), videoStartPos);
|
||||||
simpleExoPlayer.setPlayWhenReady(false);
|
simpleExoPlayer.setPlayWhenReady(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,15 +675,16 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
videoThumbnailUrl = info.thumbnail_url;
|
videoThumbnailUrl = info.thumbnail_url;
|
||||||
videoTitle = info.name;
|
videoTitle = info.name;
|
||||||
|
|
||||||
initThumbnail();
|
initThumbnail(videoThumbnailUrl);
|
||||||
|
|
||||||
if (simpleExoPlayer.getCurrentWindowIndex() != playbackManager.getCurrentSourceIndex()) {
|
if (simpleExoPlayer.getCurrentWindowIndex() != playbackManager.getCurrentSourceIndex()) {
|
||||||
if (DEBUG) Log.w(TAG, "Rewinding to correct window");
|
if (DEBUG) Log.w(TAG, "Rewinding to correct window");
|
||||||
if (simpleExoPlayer.getCurrentTimeline().getWindowCount() > playbackManager.getCurrentSourceIndex()) {
|
if (simpleExoPlayer.getCurrentTimeline().getWindowCount() > playbackManager.getCurrentSourceIndex()) {
|
||||||
simpleExoPlayer.seekToDefaultPosition(playbackManager.getCurrentSourceIndex());
|
simpleExoPlayer.seekToDefaultPosition(playbackManager.getCurrentSourceIndex());
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(context, "Play Queue out of sync", Toast.LENGTH_SHORT).show();
|
if (DEBUG) Log.w(TAG, "Play Queue out of sync");
|
||||||
simpleExoPlayer.seekToDefaultPosition();
|
playbackManager.reset();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,26 +717,12 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
public void onVideoPlayPause() {
|
public void onVideoPlayPause() {
|
||||||
if (DEBUG) Log.d(TAG, "onVideoPlayPause() called");
|
if (DEBUG) Log.d(TAG, "onVideoPlayPause() called");
|
||||||
|
|
||||||
if (currentState == STATE_COMPLETED) {
|
|
||||||
onVideoPlayPauseRepeat();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isPlaying()) audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
if (!isPlaying()) audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||||
else audioManager.abandonAudioFocus(this);
|
else audioManager.abandonAudioFocus(this);
|
||||||
|
|
||||||
simpleExoPlayer.setPlayWhenReady(!isPlaying());
|
simpleExoPlayer.setPlayWhenReady(!isPlaying());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onVideoPlayPauseRepeat() {
|
|
||||||
if (DEBUG) Log.d(TAG, "onVideoPlayPauseRepeat() called");
|
|
||||||
changeState(STATE_LOADING);
|
|
||||||
setVideoStartPos(0);
|
|
||||||
simpleExoPlayer.seekTo(0);
|
|
||||||
simpleExoPlayer.setPlayWhenReady(true);
|
|
||||||
audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onFastRewind() {
|
public void onFastRewind() {
|
||||||
if (DEBUG) Log.d(TAG, "onFastRewind() called");
|
if (DEBUG) Log.d(TAG, "onFastRewind() called");
|
||||||
seekBy(-FAST_FORWARD_REWIND_AMOUNT);
|
seekBy(-FAST_FORWARD_REWIND_AMOUNT);
|
||||||
|
@ -704,10 +733,6 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
seekBy(FAST_FORWARD_REWIND_AMOUNT);
|
seekBy(FAST_FORWARD_REWIND_AMOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onThumbnailReceived(Bitmap thumbnail) {
|
|
||||||
if (DEBUG) Log.d(TAG, "onThumbnailReceived() called with: thumbnail = [" + thumbnail + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void seekBy(int milliSeconds) {
|
public void seekBy(int milliSeconds) {
|
||||||
if (DEBUG) Log.d(TAG, "seekBy() called with: milliSeconds = [" + milliSeconds + "]");
|
if (DEBUG) Log.d(TAG, "seekBy() called with: milliSeconds = [" + milliSeconds + "]");
|
||||||
if (simpleExoPlayer == null || (isCompleted() && milliSeconds > 0) || ((milliSeconds < 0 && simpleExoPlayer.getCurrentPosition() == 0)))
|
if (simpleExoPlayer == null || (isCompleted() && milliSeconds > 0) || ((milliSeconds < 0 && simpleExoPlayer.getCurrentPosition() == 0)))
|
||||||
|
@ -746,14 +771,13 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void startProgressLoop() {
|
protected void startProgressLoop() {
|
||||||
progressLoop.removeCallbacksAndMessages(null);
|
if (progressUpdateReactor != null) progressUpdateReactor.dispose();
|
||||||
isProgressLoopRunning.set(true);
|
progressUpdateReactor = getProgressReactor();
|
||||||
progressLoop.post(progressUpdate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void stopProgressLoop() {
|
protected void stopProgressLoop() {
|
||||||
isProgressLoopRunning.set(false);
|
if (progressUpdateReactor != null) progressUpdateReactor.dispose();
|
||||||
progressLoop.removeCallbacksAndMessages(null);
|
progressUpdateReactor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void tryDeleteCacheFiles(Context context) {
|
protected void tryDeleteCacheFiles(Context context) {
|
||||||
|
@ -902,4 +926,8 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
public boolean isPlayerReady() {
|
public boolean isPlayerReady() {
|
||||||
return currentState == STATE_PLAYING || currentState == STATE_COMPLETED || currentState == STATE_PAUSED;
|
return currentState == STATE_PLAYING || currentState == STATE_COMPLETED || currentState == STATE_PAUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isProgressLoopRunning() {
|
||||||
|
return progressUpdateReactor != null && !progressUpdateReactor.isDisposed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,7 +217,7 @@ public class MainVideoPlayer extends Activity {
|
||||||
MySimpleOnGestureListener listener = new MySimpleOnGestureListener();
|
MySimpleOnGestureListener listener = new MySimpleOnGestureListener();
|
||||||
gestureDetector = new GestureDetector(context, listener);
|
gestureDetector = new GestureDetector(context, listener);
|
||||||
gestureDetector.setIsLongpressEnabled(false);
|
gestureDetector.setIsLongpressEnabled(false);
|
||||||
playerImpl.getRootView().setOnTouchListener(listener);
|
getRootView().setOnTouchListener(listener);
|
||||||
|
|
||||||
repeatButton.setOnClickListener(this);
|
repeatButton.setOnClickListener(this);
|
||||||
playPauseButton.setOnClickListener(this);
|
playPauseButton.setOnClickListener(this);
|
||||||
|
@ -252,8 +252,10 @@ public class MainVideoPlayer extends Activity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFullScreenButtonClicked() {
|
public void onFullScreenButtonClicked() {
|
||||||
|
super.onFullScreenButtonClicked();
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
|
if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
|
||||||
if (playerImpl.getPlayer() == null) return;
|
if (simpleExoPlayer == null) return;
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
&& !PermissionHelper.checkSystemAlertWindowPermission(MainVideoPlayer.this)) {
|
&& !PermissionHelper.checkSystemAlertWindowPermission(MainVideoPlayer.this)) {
|
||||||
|
@ -261,11 +263,11 @@ public class MainVideoPlayer extends Activity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.startService(NavigationHelper.getOpenVideoPlayerIntent(context, PopupVideoPlayer.class, playerImpl));
|
context.startService(NavigationHelper.getOpenVideoPlayerIntent(context, PopupVideoPlayer.class, this));
|
||||||
if (playerImpl != null) playerImpl.destroyPlayer();
|
destroyPlayer();
|
||||||
|
|
||||||
((View) getControlAnimationView().getParent()).setVisibility(View.GONE);
|
((View) getControlAnimationView().getParent()).setVisibility(View.GONE);
|
||||||
MainVideoPlayer.this.finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -302,10 +304,10 @@ public class MainVideoPlayer extends Activity {
|
||||||
|
|
||||||
if (getCurrentState() != STATE_COMPLETED) {
|
if (getCurrentState() != STATE_COMPLETED) {
|
||||||
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
||||||
animateView(playerImpl.getControlsRoot(), true, 300, 0, new Runnable() {
|
animateView(getControlsRoot(), true, 300, 0, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (getCurrentState() == STATE_PLAYING && !playerImpl.isSomePopupMenuVisible()) {
|
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
|
||||||
hideControls(300, DEFAULT_CONTROLS_HIDE_TIME);
|
hideControls(300, DEFAULT_CONTROLS_HIDE_TIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,7 +323,7 @@ public class MainVideoPlayer extends Activity {
|
||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
super.onStopTrackingTouch(seekBar);
|
super.onStopTrackingTouch(seekBar);
|
||||||
if (playerImpl.wasPlaying()) {
|
if (wasPlaying()) {
|
||||||
hideControls(100, 0);
|
hideControls(100, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,11 +459,6 @@ public class MainVideoPlayer extends Activity {
|
||||||
public ImageButton getPlayPauseButton() {
|
public ImageButton getPlayPauseButton() {
|
||||||
return playPauseButton;
|
return playPauseButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRepeatModeChanged(int i) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
||||||
|
|
|
@ -67,6 +67,10 @@ import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.player.old.PlayVideoActivity;
|
import org.schabi.newpipe.player.old.PlayVideoActivity;
|
||||||
|
import org.schabi.newpipe.player.playback.PlaybackManager;
|
||||||
|
import org.schabi.newpipe.playlist.PlayQueue;
|
||||||
|
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||||
|
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
|
@ -115,14 +119,7 @@ public class PopupVideoPlayer extends Service {
|
||||||
private float minimumWidth, minimumHeight;
|
private float minimumWidth, minimumHeight;
|
||||||
private float maximumWidth, maximumHeight;
|
private float maximumWidth, maximumHeight;
|
||||||
|
|
||||||
private final String setAlphaMethodName = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) ? "setImageAlpha" : "setAlpha";
|
|
||||||
private NotificationManager notificationManager;
|
private NotificationManager notificationManager;
|
||||||
private NotificationCompat.Builder notBuilder;
|
|
||||||
private RemoteViews notRemoteView;
|
|
||||||
|
|
||||||
|
|
||||||
private ImageLoader imageLoader = ImageLoader.getInstance();
|
|
||||||
private DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().cacheInMemory(true).build();
|
|
||||||
|
|
||||||
private VideoPlayerImpl playerImpl;
|
private VideoPlayerImpl playerImpl;
|
||||||
private Disposable currentWorker;
|
private Disposable currentWorker;
|
||||||
|
@ -148,7 +145,6 @@ public class PopupVideoPlayer extends Service {
|
||||||
if (playerImpl.getPlayer() == null) initPopup();
|
if (playerImpl.getPlayer() == null) initPopup();
|
||||||
if (!playerImpl.isPlaying()) playerImpl.getPlayer().setPlayWhenReady(true);
|
if (!playerImpl.isPlaying()) playerImpl.getPlayer().setPlayWhenReady(true);
|
||||||
|
|
||||||
if (imageLoader != null) imageLoader.clearMemoryCache();
|
|
||||||
if (intent.getStringExtra(Constants.KEY_URL) != null) {
|
if (intent.getStringExtra(Constants.KEY_URL) != null) {
|
||||||
final int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
final int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||||
final String url = intent.getStringExtra(Constants.KEY_URL);
|
final String url = intent.getStringExtra(Constants.KEY_URL);
|
||||||
|
@ -245,61 +241,6 @@ public class PopupVideoPlayer extends Service {
|
||||||
windowManager.addView(rootView, windowLayoutParams);
|
windowManager.addView(rootView, windowLayoutParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Notification
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private NotificationCompat.Builder createNotification() {
|
|
||||||
notRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_popup_notification);
|
|
||||||
|
|
||||||
if (playerImpl.getVideoThumbnail() == null) notRemoteView.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
|
|
||||||
else notRemoteView.setImageViewBitmap(R.id.notificationCover, playerImpl.getVideoThumbnail());
|
|
||||||
|
|
||||||
notRemoteView.setTextViewText(R.id.notificationSongName, playerImpl.getVideoTitle());
|
|
||||||
notRemoteView.setTextViewText(R.id.notificationArtist, playerImpl.getUploaderName());
|
|
||||||
|
|
||||||
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.notificationContent,
|
|
||||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_OPEN_DETAIL), PendingIntent.FLAG_UPDATE_CURRENT));
|
|
||||||
notRemoteView.setOnClickPendingIntent(R.id.notificationRepeat,
|
|
||||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
|
|
||||||
|
|
||||||
switch (playerImpl.simpleExoPlayer.getRepeatMode()) {
|
|
||||||
case Player.REPEAT_MODE_OFF:
|
|
||||||
notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 77);
|
|
||||||
break;
|
|
||||||
case Player.REPEAT_MODE_ONE:
|
|
||||||
//todo change image
|
|
||||||
notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 168);
|
|
||||||
break;
|
|
||||||
case Player.REPEAT_MODE_ALL:
|
|
||||||
notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 255);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
|
|
||||||
.setOngoing(true)
|
|
||||||
.setSmallIcon(R.drawable.ic_play_arrow_white)
|
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
||||||
.setContent(notRemoteView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(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
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -400,25 +341,22 @@ public class PopupVideoPlayer extends Service {
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
super.destroy();
|
super.destroy();
|
||||||
if (notRemoteView != null) notRemoteView.setImageViewBitmap(R.id.notificationCover, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onThumbnailReceived(Bitmap thumbnail) {
|
public void onThumbnailReceived(Bitmap thumbnail) {
|
||||||
super.onThumbnailReceived(thumbnail);
|
super.onThumbnailReceived(thumbnail);
|
||||||
if (thumbnail != null) {
|
|
||||||
if (notRemoteView != null) notRemoteView.setImageViewBitmap(R.id.notificationCover, thumbnail);
|
|
||||||
updateNotification(-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFullScreenButtonClicked() {
|
public void onFullScreenButtonClicked() {
|
||||||
|
super.onFullScreenButtonClicked();
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
|
if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
|
||||||
Intent intent;
|
Intent intent;
|
||||||
if (!getSharedPreferences().getBoolean(getResources().getString(R.string.use_old_player_key), false)) {
|
if (!getSharedPreferences().getBoolean(getResources().getString(R.string.use_old_player_key), false)) {
|
||||||
intent = NavigationHelper.getOpenVideoPlayerIntent(context, MainVideoPlayer.class, playerImpl);
|
intent = NavigationHelper.getOpenVideoPlayerIntent(context, MainVideoPlayer.class, this);
|
||||||
if (!playerImpl.isStartedFromNewPipe()) intent.putExtra(VideoPlayer.STARTED_FROM_NEWPIPE, false);
|
if (!isStartedFromNewPipe()) intent.putExtra(VideoPlayer.STARTED_FROM_NEWPIPE, false);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
} else {
|
} else {
|
||||||
intent = new Intent(PopupVideoPlayer.this, PlayVideoActivity.class)
|
intent = new Intent(PopupVideoPlayer.this, PlayVideoActivity.class)
|
||||||
|
@ -429,31 +367,10 @@ public class PopupVideoPlayer extends Service {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
}
|
}
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
if (playerImpl != null) playerImpl.destroyPlayer();
|
destroyPlayer();
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRepeatClicked() {
|
|
||||||
super.onRepeatClicked();
|
|
||||||
switch (simpleExoPlayer.getRepeatMode()) {
|
|
||||||
case Player.REPEAT_MODE_OFF:
|
|
||||||
// Drawable didn't work on low API :/
|
|
||||||
//notRemoteView.setImageViewResource(R.id.notificationRepeat, R.drawable.ic_repeat_disabled_white);
|
|
||||||
// Set the icon to 30% opacity - 255 (max) * .3
|
|
||||||
notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 77);
|
|
||||||
break;
|
|
||||||
case Player.REPEAT_MODE_ONE:
|
|
||||||
// todo change image
|
|
||||||
notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 168);
|
|
||||||
break;
|
|
||||||
case Player.REPEAT_MODE_ALL:
|
|
||||||
notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 255);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
updateNotification(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDismiss(PopupMenu menu) {
|
public void onDismiss(PopupMenu menu) {
|
||||||
super.onDismiss(menu);
|
super.onDismiss(menu);
|
||||||
|
@ -469,7 +386,7 @@ public class PopupVideoPlayer extends Service {
|
||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
super.onStopTrackingTouch(seekBar);
|
super.onStopTrackingTouch(seekBar);
|
||||||
if (playerImpl.wasPlaying()) {
|
if (wasPlaying()) {
|
||||||
hideControls(100, 0);
|
hideControls(100, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -507,13 +424,13 @@ public class PopupVideoPlayer extends Service {
|
||||||
onVideoClose();
|
onVideoClose();
|
||||||
break;
|
break;
|
||||||
case ACTION_PLAY_PAUSE:
|
case ACTION_PLAY_PAUSE:
|
||||||
playerImpl.onVideoPlayPause();
|
onVideoPlayPause();
|
||||||
break;
|
break;
|
||||||
case ACTION_OPEN_DETAIL:
|
case ACTION_OPEN_DETAIL:
|
||||||
onOpenDetail(PopupVideoPlayer.this, playerImpl.getVideoUrl(), playerImpl.getVideoTitle());
|
onOpenDetail(PopupVideoPlayer.this, getVideoUrl(), getVideoTitle());
|
||||||
break;
|
break;
|
||||||
case ACTION_REPEAT:
|
case ACTION_REPEAT:
|
||||||
playerImpl.onRepeatClicked();
|
onRepeatClicked();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -524,38 +441,32 @@ public class PopupVideoPlayer extends Service {
|
||||||
@Override
|
@Override
|
||||||
public void onLoading() {
|
public void onLoading() {
|
||||||
super.onLoading();
|
super.onLoading();
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaying() {
|
public void onPlaying() {
|
||||||
super.onPlaying();
|
super.onPlaying();
|
||||||
updateNotification(R.drawable.ic_pause_white);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBuffering() {
|
public void onBuffering() {
|
||||||
super.onBuffering();
|
super.onBuffering();
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPaused() {
|
public void onPaused() {
|
||||||
super.onPaused();
|
super.onPaused();
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
|
||||||
showAndAnimateControl(R.drawable.ic_play_arrow_white, false);
|
showAndAnimateControl(R.drawable.ic_play_arrow_white, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPausedSeek() {
|
public void onPausedSeek() {
|
||||||
super.onPausedSeek();
|
super.onPausedSeek();
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCompleted() {
|
public void onCompleted() {
|
||||||
super.onCompleted();
|
super.onCompleted();
|
||||||
updateNotification(R.drawable.ic_replay_white);
|
|
||||||
showAndAnimateControl(R.drawable.ic_replay_white, false);
|
showAndAnimateControl(R.drawable.ic_replay_white, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,10 +475,6 @@ public class PopupVideoPlayer extends Service {
|
||||||
public TextView getResizingIndicator() {
|
public TextView getResizingIndicator() {
|
||||||
return resizingIndicator;
|
return resizingIndicator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRepeatModeChanged(int i) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
||||||
|
@ -746,49 +653,16 @@ public class PopupVideoPlayer extends Service {
|
||||||
this.serviceId = serviceId;
|
this.serviceId = serviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onReceive(StreamInfo info) {
|
public void onReceive(final StreamInfo info) {
|
||||||
playerImpl.setVideoTitle(info.name);
|
|
||||||
playerImpl.setVideoUrl(info.url);
|
|
||||||
playerImpl.setVideoThumbnailUrl(info.thumbnail_url);
|
|
||||||
playerImpl.setUploaderName(info.uploader_name);
|
|
||||||
|
|
||||||
playerImpl.setVideoStreamsList(new ArrayList<>(ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false)));
|
|
||||||
playerImpl.setAudioStream(ListHelper.getHighestQualityAudio(info.audio_streams));
|
|
||||||
|
|
||||||
int defaultResolution = ListHelper.getPopupDefaultResolutionIndex(context, playerImpl.getVideoStreamsList());
|
|
||||||
playerImpl.setSelectedIndexStream(defaultResolution);
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "FetcherHandler.StreamExtractor: chosen = "
|
|
||||||
+ MediaFormat.getNameById(info.video_streams.get(defaultResolution).format) + " "
|
|
||||||
+ info.video_streams.get(defaultResolution).resolution + " > "
|
|
||||||
+ info.video_streams.get(defaultResolution).url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.start_position > 0) playerImpl.setVideoStartPos(info.start_position * 1000);
|
if (info.start_position > 0) playerImpl.setVideoStartPos(info.start_position * 1000);
|
||||||
else playerImpl.setVideoStartPos(-1);
|
else playerImpl.setVideoStartPos(-1);
|
||||||
|
|
||||||
mainHandler.post(new Runnable() {
|
mainHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
playerImpl.playQueue = new SinglePlayQueue(info, PlayQueueItem.DEFAULT_QUALITY);
|
||||||
playerImpl.playQueue.init();
|
playerImpl.playQueue.init();
|
||||||
}
|
playerImpl.playbackManager = new PlaybackManager(playerImpl, playerImpl.playQueue);
|
||||||
});
|
|
||||||
|
|
||||||
imageLoader.resume();
|
|
||||||
imageLoader.loadImage(info.thumbnail_url, displayImageOptions, new SimpleImageLoadingListener() {
|
|
||||||
@Override
|
|
||||||
public void onLoadingComplete(final String imageUri, View view, final Bitmap loadedImage) {
|
|
||||||
if (playerImpl == null || playerImpl.getPlayer() == null) return;
|
|
||||||
if (DEBUG) Log.d(TAG, "FetcherHandler.imageLoader.onLoadingComplete() called with: imageUri = [" + imageUri + "]");
|
|
||||||
mainHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
playerImpl.setVideoThumbnail(loadedImage);
|
|
||||||
if (loadedImage != null) notRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage);
|
|
||||||
updateNotification(-1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -309,7 +309,7 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
|
||||||
public void onLoading() {
|
public void onLoading() {
|
||||||
if (DEBUG) Log.d(TAG, "onLoading() called");
|
if (DEBUG) Log.d(TAG, "onLoading() called");
|
||||||
|
|
||||||
if (!isProgressLoopRunning.get()) startProgressLoop();
|
if (!isProgressLoopRunning()) startProgressLoop();
|
||||||
|
|
||||||
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
||||||
animateView(controlsRoot, false, 300);
|
animateView(controlsRoot, false, 300);
|
||||||
|
@ -331,7 +331,7 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
|
||||||
@Override
|
@Override
|
||||||
public void onPlaying() {
|
public void onPlaying() {
|
||||||
if (DEBUG) Log.d(TAG, "onPlaying() called");
|
if (DEBUG) Log.d(TAG, "onPlaying() called");
|
||||||
if (!isProgressLoopRunning.get()) startProgressLoop();
|
if (!isProgressLoopRunning()) startProgressLoop();
|
||||||
showAndAnimateControl(-1, true);
|
showAndAnimateControl(-1, true);
|
||||||
loadingPanel.setVisibility(View.GONE);
|
loadingPanel.setVisibility(View.GONE);
|
||||||
showControlsThenHide();
|
showControlsThenHide();
|
||||||
|
@ -362,7 +362,7 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
|
||||||
public void onCompleted() {
|
public void onCompleted() {
|
||||||
if (DEBUG) Log.d(TAG, "onCompleted() called");
|
if (DEBUG) Log.d(TAG, "onCompleted() called");
|
||||||
|
|
||||||
if (isProgressLoopRunning.get()) stopProgressLoop();
|
if (isProgressLoopRunning()) stopProgressLoop();
|
||||||
|
|
||||||
showControls(500);
|
showControls(500);
|
||||||
animateView(endScreen, true, 800);
|
animateView(endScreen, true, 800);
|
||||||
|
@ -445,22 +445,15 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onVideoPlayPauseRepeat() {
|
|
||||||
if (DEBUG) Log.d(TAG, "onVideoPlayPauseRepeat() called");
|
|
||||||
if (qualityChanged) {
|
|
||||||
setVideoStartPos(0);
|
|
||||||
//play(true);
|
|
||||||
} else super.onVideoPlayPauseRepeat();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onThumbnailReceived(Bitmap thumbnail) {
|
public void onThumbnailReceived(Bitmap thumbnail) {
|
||||||
super.onThumbnailReceived(thumbnail);
|
super.onThumbnailReceived(thumbnail);
|
||||||
if (thumbnail != null) endScreen.setImageBitmap(thumbnail);
|
if (thumbnail != null) endScreen.setImageBitmap(thumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void onFullScreenButtonClicked();
|
protected void onFullScreenButtonClicked() {
|
||||||
|
if (!isPlayerReady()) return;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFastRewind() {
|
public void onFastRewind() {
|
||||||
|
@ -501,8 +494,8 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
|
||||||
if (qualityPopupMenuGroupId == menuItem.getGroupId()) {
|
if (qualityPopupMenuGroupId == menuItem.getGroupId()) {
|
||||||
if (selectedIndexStream == menuItem.getItemId()) return true;
|
if (selectedIndexStream == menuItem.getItemId()) return true;
|
||||||
|
|
||||||
restoreQueueIndex = playQueue.getIndex();
|
queueStartPos = playQueue.getIndex();
|
||||||
restoreWindowPos = simpleExoPlayer.getCurrentPosition();
|
videoStartPos = simpleExoPlayer.getCurrentPosition();
|
||||||
playbackManager.updateCurrent(menuItem.getItemId());
|
playbackManager.updateCurrent(menuItem.getItemId());
|
||||||
|
|
||||||
qualityTextView.setText(menuItem.getTitle());
|
qualityTextView.setText(menuItem.getTitle());
|
||||||
|
@ -580,7 +573,7 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
|
||||||
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200);
|
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200);
|
||||||
|
|
||||||
if (getCurrentState() == STATE_PAUSED_SEEK) changeState(STATE_BUFFERING);
|
if (getCurrentState() == STATE_PAUSED_SEEK) changeState(STATE_BUFFERING);
|
||||||
if (!isProgressLoopRunning.get()) startProgressLoop();
|
if (!isProgressLoopRunning()) startProgressLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -12,7 +12,7 @@ import org.schabi.newpipe.playlist.PlayQueue;
|
||||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||||
import org.schabi.newpipe.playlist.events.PlayQueueMessage;
|
import org.schabi.newpipe.playlist.events.PlayQueueMessage;
|
||||||
import org.schabi.newpipe.playlist.events.RemoveEvent;
|
import org.schabi.newpipe.playlist.events.RemoveEvent;
|
||||||
import org.schabi.newpipe.playlist.events.SwapEvent;
|
import org.schabi.newpipe.playlist.events.MoveEvent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -91,7 +91,9 @@ public class PlaybackManager {
|
||||||
|
|
||||||
public void report(final Exception error) {
|
public void report(final Exception error) {
|
||||||
// ignore error checking for now, just remove the current index
|
// ignore error checking for now, just remove the current index
|
||||||
if (error == null || !tryBlock()) return;
|
if (error == null) return;
|
||||||
|
|
||||||
|
tryBlock();
|
||||||
|
|
||||||
final int index = playQueue.getIndex();
|
final int index = playQueue.getIndex();
|
||||||
playQueue.remove(index);
|
playQueue.remove(index);
|
||||||
|
@ -101,7 +103,7 @@ public class PlaybackManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateCurrent(final int newSortedStreamsIndex) {
|
public void updateCurrent(final int newSortedStreamsIndex) {
|
||||||
if (!tryBlock()) return;
|
tryBlock();
|
||||||
|
|
||||||
PlayQueueItem item = playQueue.getCurrent();
|
PlayQueueItem item = playQueue.getCurrent();
|
||||||
item.setSortedQualityIndex(newSortedStreamsIndex);
|
item.setSortedQualityIndex(newSortedStreamsIndex);
|
||||||
|
@ -110,6 +112,13 @@ public class PlaybackManager {
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
tryBlock();
|
||||||
|
|
||||||
|
resetSources();
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if (playQueueReactor != null) playQueueReactor.cancel();
|
if (playQueueReactor != null) playQueueReactor.cancel();
|
||||||
if (disposables != null) disposables.dispose();
|
if (disposables != null) disposables.dispose();
|
||||||
|
@ -143,8 +152,8 @@ public class PlaybackManager {
|
||||||
switch (event.type()) {
|
switch (event.type()) {
|
||||||
case INIT:
|
case INIT:
|
||||||
isBlocked = true;
|
isBlocked = true;
|
||||||
|
break;
|
||||||
case APPEND:
|
case APPEND:
|
||||||
load();
|
|
||||||
break;
|
break;
|
||||||
case SELECT:
|
case SELECT:
|
||||||
onSelect();
|
onSelect();
|
||||||
|
@ -153,10 +162,9 @@ public class PlaybackManager {
|
||||||
final RemoveEvent removeEvent = (RemoveEvent) event;
|
final RemoveEvent removeEvent = (RemoveEvent) event;
|
||||||
remove(removeEvent.index());
|
remove(removeEvent.index());
|
||||||
break;
|
break;
|
||||||
case SWAP:
|
case MOVE:
|
||||||
final SwapEvent swapEvent = (SwapEvent) event;
|
final MoveEvent moveEvent = (MoveEvent) event;
|
||||||
swap(swapEvent.getFrom(), swapEvent.getTo());
|
move(moveEvent.getFrom(), moveEvent.getTo());
|
||||||
load();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -167,6 +175,8 @@ public class PlaybackManager {
|
||||||
playQueue.fetch();
|
playQueue.fetch();
|
||||||
} else if (playQueue.isEmpty()) {
|
} else if (playQueue.isEmpty()) {
|
||||||
playbackListener.shutdown();
|
playbackListener.shutdown();
|
||||||
|
} else {
|
||||||
|
load(); // All event warrants a load
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playQueueReactor != null) playQueueReactor.request(1);
|
if (playQueueReactor != null) playQueueReactor.request(1);
|
||||||
|
@ -176,9 +186,7 @@ public class PlaybackManager {
|
||||||
public void onError(@NonNull Throwable e) {}
|
public void onError(@NonNull Throwable e) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete() {
|
public void onComplete() {}
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,21 +222,26 @@ public class PlaybackManager {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Responds to a SELECT event.
|
* Responds to a SELECT event.
|
||||||
* If the selected item is already loaded, then we simply synchronize and
|
*
|
||||||
|
* If the player is being blocked, then nothing should happen.
|
||||||
|
*
|
||||||
|
* Otherwise:
|
||||||
|
*
|
||||||
|
* When the selected item is already loaded, then we simply synchronize and
|
||||||
* start loading some more items.
|
* start loading some more items.
|
||||||
*
|
*
|
||||||
* If the current item has not been fully loaded, then the player will be
|
* When the current item has not been fully loaded, then the player will be
|
||||||
* blocked. The sources will be reset and reloaded, to conserve memory.
|
* blocked. The sources will be reset and reloaded, to conserve memory.
|
||||||
* */
|
* */
|
||||||
private void onSelect() {
|
private void onSelect() {
|
||||||
if (isCurrentIndexLoaded() && !isBlocked) {
|
if (isBlocked) return;
|
||||||
|
|
||||||
|
if (isCurrentIndexLoaded()) {
|
||||||
sync();
|
sync();
|
||||||
} else {
|
} else {
|
||||||
tryBlock();
|
tryBlock();
|
||||||
resetSources();
|
resetSources();
|
||||||
}
|
}
|
||||||
|
|
||||||
load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sync() {
|
private void sync() {
|
||||||
|
@ -249,6 +262,7 @@ public class PlaybackManager {
|
||||||
final int currentIndex = playQueue.getIndex();
|
final int currentIndex = playQueue.getIndex();
|
||||||
final PlayQueueItem currentItem = playQueue.get(currentIndex);
|
final PlayQueueItem currentItem = playQueue.get(currentIndex);
|
||||||
if (currentItem != null) load(currentItem);
|
if (currentItem != null) load(currentItem);
|
||||||
|
else return;
|
||||||
|
|
||||||
// The rest are just for seamless playback
|
// The rest are just for seamless playback
|
||||||
final int leftBound = Math.max(0, currentIndex - WINDOW_SIZE);
|
final int leftBound = Math.max(0, currentIndex - WINDOW_SIZE);
|
||||||
|
@ -270,7 +284,6 @@ public class PlaybackManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disposables.size() > 8) disposables.clear();
|
|
||||||
disposables.add(d);
|
disposables.add(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +341,7 @@ public class PlaybackManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void swap(final int source, final int target) {
|
private void move(final int source, final int target) {
|
||||||
final int sourceIndex = sourceToQueueIndex.indexOf(source);
|
final int sourceIndex = sourceToQueueIndex.indexOf(source);
|
||||||
final int targetIndex = sourceToQueueIndex.indexOf(target);
|
final int targetIndex = sourceToQueueIndex.indexOf(target);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import org.schabi.newpipe.playlist.events.InitEvent;
|
||||||
import org.schabi.newpipe.playlist.events.PlayQueueMessage;
|
import org.schabi.newpipe.playlist.events.PlayQueueMessage;
|
||||||
import org.schabi.newpipe.playlist.events.RemoveEvent;
|
import org.schabi.newpipe.playlist.events.RemoveEvent;
|
||||||
import org.schabi.newpipe.playlist.events.SelectEvent;
|
import org.schabi.newpipe.playlist.events.SelectEvent;
|
||||||
import org.schabi.newpipe.playlist.events.SwapEvent;
|
import org.schabi.newpipe.playlist.events.MoveEvent;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -28,7 +28,7 @@ public abstract class PlayQueue implements Serializable {
|
||||||
private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode());
|
private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode());
|
||||||
private final int INDEX_CHANGE_DEBOUNCE = 350;
|
private final int INDEX_CHANGE_DEBOUNCE = 350;
|
||||||
|
|
||||||
public static final boolean DEBUG = false;
|
public static final boolean DEBUG = true;
|
||||||
|
|
||||||
private final ArrayList<PlayQueueItem> streams;
|
private final ArrayList<PlayQueueItem> streams;
|
||||||
private final AtomicInteger queueIndex;
|
private final AtomicInteger queueIndex;
|
||||||
|
@ -178,7 +178,7 @@ public abstract class PlayQueue implements Serializable {
|
||||||
queueIndex.set(newIndex);
|
queueIndex.set(newIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcast(new SwapEvent(source, target));
|
broadcast(new MoveEvent(source, target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
package org.schabi.newpipe.playlist.events;
|
package org.schabi.newpipe.playlist.events;
|
||||||
|
|
||||||
|
|
||||||
public class SwapEvent implements PlayQueueMessage {
|
public class MoveEvent implements PlayQueueMessage {
|
||||||
final private int from;
|
final private int from;
|
||||||
final private int to;
|
final private int to;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlayQueueEvent type() {
|
public PlayQueueEvent type() {
|
||||||
return PlayQueueEvent.SWAP;
|
return PlayQueueEvent.MOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SwapEvent(final int from, final int to) {
|
public MoveEvent(final int from, final int to) {
|
||||||
this.from = from;
|
this.from = from;
|
||||||
this.to = to;
|
this.to = to;
|
||||||
}
|
}
|
|
@ -16,6 +16,6 @@ public enum PlayQueueEvent {
|
||||||
REMOVE,
|
REMOVE,
|
||||||
|
|
||||||
// sent when two streams swap place in the play queue
|
// sent when two streams swap place in the play queue
|
||||||
SWAP
|
MOVE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.schabi.newpipe.playlist.events;
|
package org.schabi.newpipe.playlist.events;
|
||||||
|
|
||||||
public interface PlayQueueMessage {
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public interface PlayQueueMessage extends Serializable {
|
||||||
PlayQueueEvent type();
|
PlayQueueEvent type();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue