mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +00:00 
			
		
		
		
	-Fixed memory leak due to permanent remote view bitmap references.
-Removed redundant code in popup player.
This commit is contained in:
		 John Zhen M
					John Zhen M
				
			
				
					committed by
					
						 John Zhen Mo
						John Zhen Mo
					
				
			
			
				
	
			
			
			 John Zhen Mo
						John Zhen Mo
					
				
			
						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(); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user