From fd7a669a539e6c719df94cb65378ae28549acea8 Mon Sep 17 00:00:00 2001 From: Vasily Date: Thu, 27 Dec 2018 12:04:23 +0200 Subject: [PATCH 01/22] Saving streams positions and resume it --- .../schabi/newpipe/database/Migrations.java | 1 + .../history/dao/StreamHistoryDAO.java | 5 +++ .../history/model/StreamHistoryEntity.java | 19 +++++++++-- .../local/history/HistoryRecordManager.java | 21 ++++++++++-- .../newpipe/player/BackgroundPlayer.java | 1 + .../org/schabi/newpipe/player/BasePlayer.java | 32 +++++++++++++++++-- .../newpipe/player/MainVideoPlayer.java | 6 ++++ .../newpipe/player/PopupVideoPlayer.java | 1 + 8 files changed, 79 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/database/Migrations.java b/app/src/main/java/org/schabi/newpipe/database/Migrations.java index 239fc02bbd9..656599a0c7e 100644 --- a/app/src/main/java/org/schabi/newpipe/database/Migrations.java +++ b/app/src/main/java/org/schabi/newpipe/database/Migrations.java @@ -8,6 +8,7 @@ public class Migrations { public static final int DB_VER_11_0 = 1; public static final int DB_VER_12_0 = 2; + //TODO migration for stream position in history public static final Migration MIGRATION_11_12 = new Migration(DB_VER_11_0, DB_VER_12_0) { @Override diff --git a/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java b/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java index 847153e122a..4453ed00748 100644 --- a/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java +++ b/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java @@ -31,6 +31,11 @@ public abstract class StreamHistoryDAO implements HistoryDAO> getAll(); diff --git a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java index b553f437d8c..37a0ccd0039 100644 --- a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java +++ b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java @@ -31,6 +31,7 @@ public class StreamHistoryEntity { final public static String JOIN_STREAM_ID = "stream_id"; final public static String STREAM_ACCESS_DATE = "access_date"; final public static String STREAM_REPEAT_COUNT = "repeat_count"; + final public static String STREAM_POSITION = "position"; @ColumnInfo(name = JOIN_STREAM_ID) private long streamUid; @@ -42,15 +43,19 @@ public class StreamHistoryEntity { @ColumnInfo(name = STREAM_REPEAT_COUNT) private long repeatCount; - public StreamHistoryEntity(long streamUid, @NonNull Date accessDate, long repeatCount) { + @ColumnInfo(name = STREAM_POSITION) + private long position; + + public StreamHistoryEntity(long streamUid, @NonNull Date accessDate, long repeatCount, long position) { this.streamUid = streamUid; this.accessDate = accessDate; this.repeatCount = repeatCount; + this.position = position; } @Ignore - public StreamHistoryEntity(long streamUid, @NonNull Date accessDate) { - this(streamUid, accessDate, 1); + public StreamHistoryEntity(long streamUid, @NonNull Date accessDate, long position) { + this(streamUid, accessDate, 1, position); } public long getStreamUid() { @@ -76,4 +81,12 @@ public long getRepeatCount() { public void setRepeatCount(long repeatCount) { this.repeatCount = repeatCount; } + + public long getPosition() { + return position; + } + + public void setPosition(long position) { + this.position = position; + } } diff --git a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java index 56453773a7f..069d38455ea 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java @@ -75,6 +75,10 @@ public HistoryRecordManager(final Context context) { /////////////////////////////////////////////////////// public Maybe onViewed(final StreamInfo info) { + return onViewed(info, -1); + } + + public Maybe onViewed(final StreamInfo info, final long position) { if (!isStreamHistoryEnabled()) return Maybe.empty(); final Date currentTime = new Date(); @@ -85,10 +89,15 @@ public Maybe onViewed(final StreamInfo info) { if (latestEntry != null && latestEntry.getStreamUid() == streamId) { streamHistoryTable.delete(latestEntry); latestEntry.setAccessDate(currentTime); - latestEntry.setRepeatCount(latestEntry.getRepeatCount() + 1); + if (position == -1) { + latestEntry.setRepeatCount(latestEntry.getRepeatCount() + 1); + } else { + latestEntry.setPosition(position); + } return streamHistoryTable.insert(latestEntry); } else { - return streamHistoryTable.insert(new StreamHistoryEntity(streamId, currentTime)); + return streamHistoryTable.insert(new StreamHistoryEntity(streamId, currentTime, + position == -1 ? 0 : position)); } })).subscribeOn(Schedulers.io()); } @@ -107,6 +116,14 @@ public Flowable> getStreamHistory() { return streamHistoryTable.getHistory().subscribeOn(Schedulers.io()); } + + public Maybe getStreamHistory(final StreamInfo info) { + return Maybe.fromCallable(() -> { + final long streamId = streamTable.upsert(new StreamEntity(info)); + return streamHistoryTable.getOne(streamId); + }).subscribeOn(Schedulers.io()); + } + public Flowable> getStreamStatistics() { return streamHistoryTable.getStatistics().subscribeOn(Schedulers.io()); } diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java index 91faa101456..c96f27ee9a2 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -145,6 +145,7 @@ private void onClose() { lockManager.releaseWifiAndCpu(); } if (basePlayerImpl != null) { + basePlayerImpl.saveCurrentPosition(); basePlayerImpl.stopActivityBinding(); basePlayerImpl.destroy(); } diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index d1b06c9c5c2..af8dfb63d3d 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -19,6 +19,7 @@ package org.schabi.newpipe.player; +import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -870,10 +871,24 @@ public void showUnrecoverableError(Exception exception) { errorToast.show(); } - public void onPrepared(boolean playWhenReady) { + public void onPrepared(final boolean playWhenReady) { if (DEBUG) Log.d(TAG, "onPrepared() called with: playWhenReady = [" + playWhenReady + "]"); if (playWhenReady) audioReactor.requestAudioFocus(); - changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); + if (currentMetadata != null) { + final Disposable d = recordManager.getStreamHistory(currentMetadata.getMetadata()).onErrorComplete().subscribe( + history -> { + seekTo(history.getPosition()); + changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); + }, + error -> { + Log.e(TAG, "Player resume failure: ", error); + changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); + } + ); + databaseUpdateReactor.add(d); + } else { + changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); + } } public void onPlay() { @@ -1214,4 +1229,17 @@ public void setRecovery(final int queuePos, final long windowPos) { public boolean gotDestroyed() { return simpleExoPlayer == null; } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @SuppressLint("CheckResult") + public void saveCurrentPosition() { + if (currentMetadata == null) return; + final StreamInfo currentInfo = currentMetadata.getMetadata(); + final long currentPosition = simpleExoPlayer.getCurrentPosition(); + recordManager.onViewed(currentInfo, currentPosition).onErrorComplete() + .subscribe( + ignored -> {/* successful */}, + error -> Log.e(TAG, "Player onViewed() failure: ", error) + ); + } } diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index f4fea5165a1..cb36a64cba7 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -223,6 +223,12 @@ protected void onSaveInstanceState(Bundle outState) { StateSaver.tryToSave(isChangingConfigurations(), null, outState, this); } + @Override + protected void onPause() { + playerImpl.saveCurrentPosition(); + super.onPause(); + } + @Override protected void onStop() { if (DEBUG) Log.d(TAG, "onStop() called"); diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index f5c731ed9cf..291132275ae 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -323,6 +323,7 @@ public void closePopup() { if (playerImpl.getRootView() != null) { windowManager.removeView(playerImpl.getRootView()); } + playerImpl.saveCurrentPosition(); playerImpl.setRootView(null); playerImpl.stopActivityBinding(); playerImpl.destroy(); From 7fb6274ef44e7b14f1dc28aec94a430e4dccf389 Mon Sep 17 00:00:00 2001 From: Vasily Date: Thu, 27 Dec 2018 14:51:51 +0200 Subject: [PATCH 02/22] Show watch position on VideoDetailFragment --- .../history/dao/StreamHistoryDAO.java | 6 +-- .../fragments/detail/VideoDetailFragment.java | 48 +++++++++++++++++-- .../local/history/HistoryRecordManager.java | 6 +-- .../org/schabi/newpipe/player/BasePlayer.java | 9 +++- .../progress_soundcloud_horizontal_dark.xml | 15 ++++++ .../progress_soundcloud_horizontal_light.xml | 15 ++++++ .../progress_youtube_horizontal_dark.xml | 15 ++++++ .../progress_youtube_horizontal_light.xml | 15 ++++++ .../fragment_video_detail.xml | 38 +++++++++++++++ .../main/res/layout/fragment_video_detail.xml | 38 +++++++++++++++ .../main/res/values-v21/styles_services.xml | 3 ++ app/src/main/res/values/attrs.xml | 1 + app/src/main/res/values/styles.xml | 2 + app/src/main/res/values/styles_services.xml | 3 ++ 14 files changed, 203 insertions(+), 11 deletions(-) create mode 100644 app/src/main/res/drawable/progress_soundcloud_horizontal_dark.xml create mode 100644 app/src/main/res/drawable/progress_soundcloud_horizontal_light.xml create mode 100644 app/src/main/res/drawable/progress_youtube_horizontal_dark.xml create mode 100644 app/src/main/res/drawable/progress_youtube_horizontal_light.xml diff --git a/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java b/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java index 4453ed00748..99d7b45750d 100644 --- a/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java +++ b/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java @@ -31,10 +31,10 @@ public abstract class StreamHistoryDAO implements HistoryDAO sortedVideoStreams; private int selectedVideoStreamIndex = -1; @@ -153,6 +153,7 @@ public class VideoDetailFragment private View thumbnailBackgroundButton; private ImageView thumbnailImageView; private ImageView thumbnailPlayButton; + private ProgressBar positionView; private View videoTitleRoot; private TextView videoTitleTextView; @@ -166,6 +167,7 @@ public class VideoDetailFragment private TextView detailControlsDownload; private TextView appendControlsDetail; private TextView detailDurationView; + private TextView detailPositionView; private LinearLayout videoDescriptionRootLayout; private TextView videoUploadDateView; @@ -241,6 +243,8 @@ public void onResume() { // Check if it was loading when the fragment was stopped/paused, if (wasLoading.getAndSet(false)) { selectAndLoadVideo(serviceId, url, name); + } else if (currentInfo != null) { + updatePositionInfo(currentInfo); } } @@ -471,6 +475,7 @@ protected void initViews(View rootView, Bundle savedInstanceState) { thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout); thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view); thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button); + positionView = rootView.findViewById(R.id.position_view); contentRootLayoutHiding = rootView.findViewById(R.id.detail_content_root_hiding); @@ -485,6 +490,7 @@ protected void initViews(View rootView, Bundle savedInstanceState) { detailControlsDownload = rootView.findViewById(R.id.detail_controls_download); appendControlsDetail = rootView.findViewById(R.id.touch_append_detail); detailDurationView = rootView.findViewById(R.id.detail_duration_view); + detailPositionView = rootView.findViewById(R.id.detail_position_view); videoDescriptionRootLayout = rootView.findViewById(R.id.detail_description_root_layout); videoUploadDateView = rootView.findViewById(R.id.detail_upload_date_view); @@ -958,7 +964,9 @@ private void startOnExternalPlayer(@NonNull final Context context, NavigationHelper.playOnExternalPlayer(context, currentInfo.getName(), currentInfo.getUploaderName(), selectedStream); - final HistoryRecordManager recordManager = new HistoryRecordManager(requireContext()); + if (recordManager == null) { + recordManager = new HistoryRecordManager(requireContext()); + } disposables.add(recordManager.onViewed(info).onErrorComplete() .subscribe( ignored -> {/* successful */}, @@ -1105,6 +1113,8 @@ public void showLoading() { animateView(spinnerToolbar, false, 200); animateView(thumbnailPlayButton, false, 50); animateView(detailDurationView, false, 100); + animateView(detailPositionView, false, 100); + animateView(positionView, false, 50); videoTitleTextView.setText(name != null ? name : ""); videoTitleTextView.setMaxLines(1); @@ -1208,6 +1218,7 @@ public void handleResult(@NonNull StreamInfo info) { videoUploadDateView.setText(Localization.localizeDate(activity, info.getUploadDate())); } prepareDescription(info.getDescription()); + updatePositionInfo(info); animateView(spinnerToolbar, true, 500); setupActionBar(info); @@ -1323,4 +1334,35 @@ private void setRelatedStreamsVisibility(int visibility) { relatedStreamRootLayout.setVisibility(visibility); } } + + private void updatePositionInfo(final StreamInfo info) { + if (info.getDuration() <= 0) { + positionView.setVisibility(View.INVISIBLE); + detailPositionView.setVisibility(View.GONE); + return; + } + if (recordManager == null) { + recordManager = new HistoryRecordManager(requireContext()); + } + disposables.add(recordManager.getStreamHistory(info).onErrorComplete() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()).subscribe( + history -> { + final int seconds = Math.round(history.getPosition() / 1000.f); + if (seconds < info.getDuration()) { + positionView.setMax((int) info.getDuration()); + positionView.setProgress(seconds); + detailPositionView.setText(Localization.getDurationString(seconds)); + animateView(positionView, true, 500); + animateView(detailPositionView, true, 500); + } else { + animateView(positionView, false, 500); + animateView(detailPositionView, false, 500); + } + }, + error -> { + Log.e(TAG, "Player resume failure: ", error); + } + )); + } } diff --git a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java index 069d38455ea..3c42a04d3ed 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java @@ -84,9 +84,9 @@ public Maybe onViewed(final StreamInfo info, final long position) { final Date currentTime = new Date(); return Maybe.fromCallable(() -> database.runInTransaction(() -> { final long streamId = streamTable.upsert(new StreamEntity(info)); - StreamHistoryEntity latestEntry = streamHistoryTable.getLatestEntry(); + StreamHistoryEntity latestEntry = streamHistoryTable.getLatestEntry(streamId); - if (latestEntry != null && latestEntry.getStreamUid() == streamId) { + if (latestEntry != null) { streamHistoryTable.delete(latestEntry); latestEntry.setAccessDate(currentTime); if (position == -1) { @@ -120,7 +120,7 @@ public Flowable> getStreamHistory() { public Maybe getStreamHistory(final StreamInfo info) { return Maybe.fromCallable(() -> { final long streamId = streamTable.upsert(new StreamEntity(info)); - return streamHistoryTable.getOne(streamId); + return streamHistoryTable.getLatestEntry(streamId); }).subscribeOn(Schedulers.io()); } diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index af8dfb63d3d..ec5c8422338 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -875,9 +875,14 @@ public void onPrepared(final boolean playWhenReady) { if (DEBUG) Log.d(TAG, "onPrepared() called with: playWhenReady = [" + playWhenReady + "]"); if (playWhenReady) audioReactor.requestAudioFocus(); if (currentMetadata != null) { - final Disposable d = recordManager.getStreamHistory(currentMetadata.getMetadata()).onErrorComplete().subscribe( + final Disposable d = recordManager.getStreamHistory(currentMetadata.getMetadata()) + .onErrorComplete() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( history -> { - seekTo(history.getPosition()); + if (history.getPosition() <= simpleExoPlayer.getDuration()) { + seekTo(history.getPosition()); + } changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); }, error -> { diff --git a/app/src/main/res/drawable/progress_soundcloud_horizontal_dark.xml b/app/src/main/res/drawable/progress_soundcloud_horizontal_dark.xml new file mode 100644 index 00000000000..1ec9f67b6d2 --- /dev/null +++ b/app/src/main/res/drawable/progress_soundcloud_horizontal_dark.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/progress_soundcloud_horizontal_light.xml b/app/src/main/res/drawable/progress_soundcloud_horizontal_light.xml new file mode 100644 index 00000000000..c326c5c04d7 --- /dev/null +++ b/app/src/main/res/drawable/progress_soundcloud_horizontal_light.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/progress_youtube_horizontal_dark.xml b/app/src/main/res/drawable/progress_youtube_horizontal_dark.xml new file mode 100644 index 00000000000..404410f9829 --- /dev/null +++ b/app/src/main/res/drawable/progress_youtube_horizontal_dark.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/progress_youtube_horizontal_light.xml b/app/src/main/res/drawable/progress_youtube_horizontal_light.xml new file mode 100644 index 00000000000..120a6e5fb37 --- /dev/null +++ b/app/src/main/res/drawable/progress_youtube_horizontal_light.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml index 73939d60ac3..309a143514e 100644 --- a/app/src/main/res/layout-large-land/fragment_video_detail.xml +++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml @@ -95,8 +95,46 @@ tools:ignore="RtlHardcoded" tools:text="12:38" tools:visibility="visible" /> + + + + + + + + + + @color/light_soundcloud_primary_color @color/light_soundcloud_statusbar_color @color/light_soundcloud_accent_color + @drawable/progress_soundcloud_horizontal_light \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 7b879fb4c60..8ad2ffc3507 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -43,6 +43,7 @@ + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 87e19cede37..106e17f5183 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -61,6 +61,7 @@ @color/light_queue_background_color @drawable/toolbar_shadow_light @drawable/light_selector + @drawable/progress_youtube_horizontal_light @color/light_ripple_color @style/PreferenceThemeOverlay.v14.Material @@ -121,6 +122,7 @@ @color/dark_queue_background_color @drawable/toolbar_shadow_dark @drawable/dark_selector + @drawable/progress_youtube_horizontal_dark @color/dark_ripple_color @style/PreferenceThemeOverlay.v14.Material diff --git a/app/src/main/res/values/styles_services.xml b/app/src/main/res/values/styles_services.xml index 7ca9dacde44..b31172997a3 100644 --- a/app/src/main/res/values/styles_services.xml +++ b/app/src/main/res/values/styles_services.xml @@ -14,18 +14,21 @@ @color/light_soundcloud_primary_color @color/light_soundcloud_dark_color @color/light_soundcloud_accent_color + @drawable/progress_soundcloud_horizontal_light \ No newline at end of file From 2d1e5ab61fb6ec0c6239f4c49a951da5a27a9cba Mon Sep 17 00:00:00 2001 From: Vasily Date: Thu, 27 Dec 2018 15:25:56 +0200 Subject: [PATCH 03/22] Database migration --- .../main/java/org/schabi/newpipe/NewPipeDatabase.java | 3 ++- .../java/org/schabi/newpipe/database/Migrations.java | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java b/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java index 189e5aeab69..fea83269b44 100644 --- a/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java +++ b/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java @@ -8,6 +8,7 @@ import static org.schabi.newpipe.database.AppDatabase.DATABASE_NAME; import static org.schabi.newpipe.database.Migrations.MIGRATION_11_12; +import static org.schabi.newpipe.database.Migrations.MIGRATION_12_15; public final class NewPipeDatabase { @@ -20,7 +21,7 @@ private NewPipeDatabase() { private static AppDatabase getDatabase(Context context) { return Room .databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME) - .addMigrations(MIGRATION_11_12) + .addMigrations(MIGRATION_11_12, MIGRATION_12_15) .fallbackToDestructiveMigration() .build(); } diff --git a/app/src/main/java/org/schabi/newpipe/database/Migrations.java b/app/src/main/java/org/schabi/newpipe/database/Migrations.java index 656599a0c7e..a1a2ea31243 100644 --- a/app/src/main/java/org/schabi/newpipe/database/Migrations.java +++ b/app/src/main/java/org/schabi/newpipe/database/Migrations.java @@ -8,7 +8,7 @@ public class Migrations { public static final int DB_VER_11_0 = 1; public static final int DB_VER_12_0 = 2; - //TODO migration for stream position in history + public static final int DB_VER_15_0 = 3; public static final Migration MIGRATION_11_12 = new Migration(DB_VER_11_0, DB_VER_12_0) { @Override @@ -59,4 +59,11 @@ public void migrate(@NonNull SupportSQLiteDatabase database) { database.execSQL("DROP TABLE IF EXISTS watch_history"); } }; + + public static final Migration MIGRATION_12_15 = new Migration(DB_VER_12_0, DB_VER_15_0) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + database.execSQL("ALTER TABLE `stream_history` ADD COLUMN `position` INTEGER DEFAULT 0"); + } + }; } From e0b8d7c4fef3cddc0edb6f0370b01b7249212465 Mon Sep 17 00:00:00 2001 From: Vasily Date: Thu, 27 Dec 2018 15:53:20 +0200 Subject: [PATCH 04/22] Show toast on playback resumed --- .../java/org/schabi/newpipe/player/BasePlayer.java | 6 +++++- .../org/schabi/newpipe/player/MainVideoPlayer.java | 13 +++++++++++++ app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index ec5c8422338..54d5037cbdd 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -880,8 +880,9 @@ public void onPrepared(final boolean playWhenReady) { .observeOn(AndroidSchedulers.mainThread()) .subscribe( history -> { - if (history.getPosition() <= simpleExoPlayer.getDuration()) { + if (history.getPosition() > 0 && history.getPosition() <= simpleExoPlayer.getDuration()) { seekTo(history.getPosition()); + onPositionRestored(history.getPosition()); } changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); }, @@ -896,6 +897,9 @@ public void onPrepared(final boolean playWhenReady) { } } + public void onPositionRestored(long position) { + } + public void onPlay() { if (DEBUG) Log.d(TAG, "onPlay() called"); if (audioReactor == null || playQueue == null || simpleExoPlayer == null) return; diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index cb36a64cba7..be5ef2ce232 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -43,6 +43,7 @@ import android.util.Log; import android.util.TypedValue; import android.view.GestureDetector; +import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; @@ -73,6 +74,7 @@ import org.schabi.newpipe.player.resolver.VideoPlaybackResolver; import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.ListHelper; +import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.PermissionHelper; import org.schabi.newpipe.util.StateSaver; @@ -815,6 +817,17 @@ public void onPausedSeek() { getRootView().setKeepScreenOn(true); } + @Override + public void onPositionRestored(long position) { + super.onPositionRestored(position); + final Toast toast = Toast.makeText( + MainVideoPlayer.this, + getString(R.string.playback_resumed, Localization.getDurationString(Math.round(position / 1000.f))), + Toast.LENGTH_SHORT + ); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + } @Override public void onCompleted() { diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3fad6b288d3..e62ad17f82b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -524,5 +524,6 @@ Отписаться Менять громкость плеера жестом Жест громкости + Продолжение воспроизведения с %1$s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ec366ebede7..42d146b6d0b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -570,5 +570,6 @@ Maximum number of attempts before canceling the download Pause on switching to mobile data Not all downloads can be suspended, in those cases, will be restarted + Playback resumed from %1$s From 000b7b7d1b666ec304db5415e55291285f7457f3 Mon Sep 17 00:00:00 2001 From: Vasily Date: Sat, 29 Dec 2018 11:16:38 +0200 Subject: [PATCH 05/22] Dont resume playback if less then 10 seconds left --- .../schabi/newpipe/fragments/detail/VideoDetailFragment.java | 4 ++-- app/src/main/java/org/schabi/newpipe/player/BasePlayer.java | 4 +++- app/src/main/java/org/schabi/newpipe/util/Constants.java | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 1b441857047..55d2b8341a2 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -1348,8 +1348,8 @@ private void updatePositionInfo(final StreamInfo info) { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()).subscribe( history -> { - final int seconds = Math.round(history.getPosition() / 1000.f); - if (seconds < info.getDuration()) { + final int seconds = (int) (history.getPosition() / 1000.f); + if (seconds < info.getDuration() - Constants.SECONDS_MIN_LEFT) { positionView.setMax((int) info.getDuration()); positionView.setProgress(seconds); detailPositionView.setText(Localization.getDurationString(seconds)); diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index 54d5037cbdd..40ccba7d1a9 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -71,6 +71,7 @@ import org.schabi.newpipe.player.playqueue.PlayQueueAdapter; import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.resolver.MediaSourceTag; +import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.SerializedCache; @@ -880,7 +881,8 @@ public void onPrepared(final boolean playWhenReady) { .observeOn(AndroidSchedulers.mainThread()) .subscribe( history -> { - if (history.getPosition() > 0 && history.getPosition() <= simpleExoPlayer.getDuration()) { + if (history.getPosition() > 0 && + history.getPosition() < simpleExoPlayer.getDuration() - Constants.SECONDS_MIN_LEFT * 1000) { seekTo(history.getPosition()); onPositionRestored(history.getPosition()); } diff --git a/app/src/main/java/org/schabi/newpipe/util/Constants.java b/app/src/main/java/org/schabi/newpipe/util/Constants.java index b01b6df6abd..5396b4d84c7 100644 --- a/app/src/main/java/org/schabi/newpipe/util/Constants.java +++ b/app/src/main/java/org/schabi/newpipe/util/Constants.java @@ -12,4 +12,6 @@ public class Constants { public static final String KEY_MAIN_PAGE_CHANGE = "key_main_page_change"; public static final int NO_SERVICE_ID = -1; + + public static final int SECONDS_MIN_LEFT = 10; } From b86c420703da4c7d4b8bdda64530724eec84ec84 Mon Sep 17 00:00:00 2001 From: Vasily Date: Sat, 29 Dec 2018 11:48:53 +0200 Subject: [PATCH 06/22] Playback resume preference --- .../fragments/detail/VideoDetailFragment.java | 6 +- .../org/schabi/newpipe/player/BasePlayer.java | 10 ++- app/src/main/res/values-ru/strings.xml | 6 +- app/src/main/res/values-uk/strings.xml | 2 +- app/src/main/res/values/settings_keys.xml | 1 + app/src/main/res/values/strings.xml | 5 +- app/src/main/res/xml/history_settings.xml | 72 +++++++++++-------- 7 files changed, 66 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 55d2b8341a2..04af024d44c 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -1336,7 +1336,11 @@ private void setRelatedStreamsVisibility(int visibility) { } private void updatePositionInfo(final StreamInfo info) { - if (info.getDuration() <= 0) { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); + final boolean playbackResumeEnabled = + prefs.getBoolean(activity.getString(R.string.enable_watch_history_key), true) + && prefs.getBoolean(activity.getString(R.string.enable_playback_resume_key), true); + if (!playbackResumeEnabled || info.getDuration() <= 0) { positionView.setVisibility(View.INVISIBLE); detailPositionView.setVisibility(View.GONE); return; diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index 40ccba7d1a9..49425f88289 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -24,9 +24,11 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.AudioManager; +import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; @@ -881,7 +883,7 @@ public void onPrepared(final boolean playWhenReady) { .observeOn(AndroidSchedulers.mainThread()) .subscribe( history -> { - if (history.getPosition() > 0 && + if (history.getPosition() > 0 && isPlaybackResumeEnabled() && history.getPosition() < simpleExoPlayer.getDuration() - Constants.SECONDS_MIN_LEFT * 1000) { seekTo(history.getPosition()); onPositionRestored(history.getPosition()); @@ -1253,4 +1255,10 @@ public void saveCurrentPosition() { error -> Log.e(TAG, "Player onViewed() failure: ", error) ); } + + private boolean isPlaybackResumeEnabled() { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + return prefs.getBoolean(context.getString(R.string.enable_watch_history_key), true) + && prefs.getBoolean(context.getString(R.string.enable_playback_resume_key), true); + } } diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e62ad17f82b..0a491b960b0 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -198,7 +198,7 @@ История поиска Хранить запросы поиска локально - История и кэш + История просмотров Запоминать воспроизведённые потоки Возобновить при фокусе Возобновлять воспроизведение после перерывов (например, телефонных звонков) @@ -526,4 +526,8 @@ Жест громкости Продолжение воспроизведения с %1$s + Продолжать воспроизведение + Восстанавливать с последней позиции + Очистить данные + diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 1dccd25cf28..b3c9a5941cf 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -155,7 +155,7 @@ Показувати схожі під час пошуку Історія пошуків Зберігати пошукові запити локально - Історія та кеш + Історія переглядiв Вести облік перегляду відеозаписів Відновити відтворення Продовжувати відтворення опісля переривання (наприклад телефонного дзвінка) diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 300217c0998..7cd75d71671 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -147,6 +147,7 @@ use_tor enable_search_history enable_watch_history + enable_playback_resume main_page_content import_data diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 42d146b6d0b..360b1bddbe7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -91,7 +91,7 @@ Show suggestions when searching Search history Store search queries locally - History & Cache + Watch history Keep track of watched videos Resume on focus gain Continue playing after interruptions (e.g. phone calls) @@ -571,5 +571,8 @@ Pause on switching to mobile data Not all downloads can be suspended, in those cases, will be restarted Playback resumed from %1$s + Resume playback + Restore last playback position + Clear data diff --git a/app/src/main/res/xml/history_settings.xml b/app/src/main/res/xml/history_settings.xml index 2be1e534186..1cb5dc63613 100644 --- a/app/src/main/res/xml/history_settings.xml +++ b/app/src/main/res/xml/history_settings.xml @@ -1,34 +1,44 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + From 83fcb1a0f30bb3ba992f8d57f12e727216d54320 Mon Sep 17 00:00:00 2001 From: Vasily Date: Sat, 29 Dec 2018 12:15:58 +0200 Subject: [PATCH 07/22] Show player interface on playback resumed --- .../org/schabi/newpipe/player/MainVideoPlayer.java | 14 -------------- .../org/schabi/newpipe/player/VideoPlayer.java | 9 +++++++++ app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values/strings.xml | 3 +-- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index be5ef2ce232..99a804a44ce 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -43,7 +43,6 @@ import android.util.Log; import android.util.TypedValue; import android.view.GestureDetector; -import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; @@ -74,7 +73,6 @@ import org.schabi.newpipe.player.resolver.VideoPlaybackResolver; import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.ListHelper; -import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.PermissionHelper; import org.schabi.newpipe.util.StateSaver; @@ -817,18 +815,6 @@ public void onPausedSeek() { getRootView().setKeepScreenOn(true); } - @Override - public void onPositionRestored(long position) { - super.onPositionRestored(position); - final Toast toast = Toast.makeText( - MainVideoPlayer.this, - getString(R.string.playback_resumed, Localization.getDurationString(Math.round(position / 1000.f))), - Toast.LENGTH_SHORT - ); - toast.setGravity(Gravity.CENTER, 0, 0); - toast.show(); - } - @Override public void onCompleted() { animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, () -> { diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index d30d9b8be87..7ff01e7d9be 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -442,6 +442,15 @@ public void onPausedSeek() { showAndAnimateControl(-1, true); } + @Override + public void onPositionRestored(long position) { + super.onPositionRestored(position); + if (!isControlsVisible()) { + controlsVisibilityHandler.removeCallbacksAndMessages(null); + controlsVisibilityHandler.postDelayed(this::showControlsThenHide, 500); + } + } + @Override public void onCompleted() { super.onCompleted(); diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0a491b960b0..9c5bab51eee 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -524,7 +524,6 @@ Отписаться Менять громкость плеера жестом Жест громкости - Продолжение воспроизведения с %1$s Продолжать воспроизведение Восстанавливать с последней позиции diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 360b1bddbe7..dee840a8936 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -570,8 +570,7 @@ Maximum number of attempts before canceling the download Pause on switching to mobile data Not all downloads can be suspended, in those cases, will be restarted - Playback resumed from %1$s - Resume playback + Resume playback Restore last playback position Clear data From fafbd5965e9808481603ba8c49d1c7dcd025cc3c Mon Sep 17 00:00:00 2001 From: Vasily Date: Sat, 29 Dec 2018 19:23:07 +0200 Subject: [PATCH 08/22] Fix bug with player state --- .../org/schabi/newpipe/player/BasePlayer.java | 29 +++++++++---------- .../schabi/newpipe/player/VideoPlayer.java | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index 49425f88289..e1e76a4dd66 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -877,24 +877,23 @@ public void showUnrecoverableError(Exception exception) { public void onPrepared(final boolean playWhenReady) { if (DEBUG) Log.d(TAG, "onPrepared() called with: playWhenReady = [" + playWhenReady + "]"); if (playWhenReady) audioReactor.requestAudioFocus(); - if (currentMetadata != null) { + if (isPlaybackResumeEnabled() && currentMetadata != null) { final Disposable d = recordManager.getStreamHistory(currentMetadata.getMetadata()) - .onErrorComplete() .observeOn(AndroidSchedulers.mainThread()) .subscribe( - history -> { - if (history.getPosition() > 0 && isPlaybackResumeEnabled() && - history.getPosition() < simpleExoPlayer.getDuration() - Constants.SECONDS_MIN_LEFT * 1000) { - seekTo(history.getPosition()); - onPositionRestored(history.getPosition()); - } - changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); - }, - error -> { - Log.e(TAG, "Player resume failure: ", error); - changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); - } - ); + history -> { + if (history.getPosition() > 0 && + history.getPosition() < simpleExoPlayer.getDuration() - Constants.SECONDS_MIN_LEFT * 1000) { + seekTo(history.getPosition()); + onPositionRestored(history.getPosition()); + } + changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); + }, + error -> { + Log.e(TAG, "Player resume failure: ", error); + changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); + } + ); databaseUpdateReactor.add(d); } else { changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index 7ff01e7d9be..7971e33909f 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -447,7 +447,7 @@ public void onPositionRestored(long position) { super.onPositionRestored(position); if (!isControlsVisible()) { controlsVisibilityHandler.removeCallbacksAndMessages(null); - controlsVisibilityHandler.postDelayed(this::showControlsThenHide, 500); + controlsVisibilityHandler.postDelayed(this::showControlsThenHide, DEFAULT_CONTROLS_DURATION); } } From d01158bc97c9cb53ff73f535d6607ff642772e37 Mon Sep 17 00:00:00 2001 From: Vasily Date: Mon, 31 Dec 2018 18:03:56 +0200 Subject: [PATCH 09/22] Increase database version --- .../main/java/org/schabi/newpipe/database/AppDatabase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java b/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java index 145a77c702f..62f3518b73e 100644 --- a/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java +++ b/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java @@ -21,7 +21,7 @@ import org.schabi.newpipe.database.subscription.SubscriptionDAO; import org.schabi.newpipe.database.subscription.SubscriptionEntity; -import static org.schabi.newpipe.database.Migrations.DB_VER_12_0; +import static org.schabi.newpipe.database.Migrations.DB_VER_15_0; @TypeConverters({Converters.class}) @Database( @@ -30,7 +30,7 @@ StreamEntity.class, StreamHistoryEntity.class, StreamStateEntity.class, PlaylistEntity.class, PlaylistStreamEntity.class, PlaylistRemoteEntity.class }, - version = DB_VER_12_0, + version = DB_VER_15_0, exportSchema = false ) public abstract class AppDatabase extends RoomDatabase { From 31300e023863b106414866594a867d5d4731e2d6 Mon Sep 17 00:00:00 2001 From: Vasily Date: Wed, 9 Jan 2019 10:44:44 +0200 Subject: [PATCH 10/22] Use StreamState --- .../org/schabi/newpipe/NewPipeDatabase.java | 3 +- .../schabi/newpipe/database/AppDatabase.java | 4 +-- .../schabi/newpipe/database/Migrations.java | 8 ----- .../history/model/StreamHistoryEntity.java | 19 ++---------- .../fragments/detail/VideoDetailFragment.java | 6 ++-- .../local/history/HistoryRecordManager.java | 18 +++-------- .../newpipe/player/BackgroundPlayer.java | 1 - .../org/schabi/newpipe/player/BasePlayer.java | 31 ++++++------------- .../newpipe/player/MainVideoPlayer.java | 2 +- .../newpipe/player/PopupVideoPlayer.java | 1 - 10 files changed, 23 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java b/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java index fea83269b44..189e5aeab69 100644 --- a/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java +++ b/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java @@ -8,7 +8,6 @@ import static org.schabi.newpipe.database.AppDatabase.DATABASE_NAME; import static org.schabi.newpipe.database.Migrations.MIGRATION_11_12; -import static org.schabi.newpipe.database.Migrations.MIGRATION_12_15; public final class NewPipeDatabase { @@ -21,7 +20,7 @@ private NewPipeDatabase() { private static AppDatabase getDatabase(Context context) { return Room .databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME) - .addMigrations(MIGRATION_11_12, MIGRATION_12_15) + .addMigrations(MIGRATION_11_12) .fallbackToDestructiveMigration() .build(); } diff --git a/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java b/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java index 62f3518b73e..145a77c702f 100644 --- a/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java +++ b/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java @@ -21,7 +21,7 @@ import org.schabi.newpipe.database.subscription.SubscriptionDAO; import org.schabi.newpipe.database.subscription.SubscriptionEntity; -import static org.schabi.newpipe.database.Migrations.DB_VER_15_0; +import static org.schabi.newpipe.database.Migrations.DB_VER_12_0; @TypeConverters({Converters.class}) @Database( @@ -30,7 +30,7 @@ StreamEntity.class, StreamHistoryEntity.class, StreamStateEntity.class, PlaylistEntity.class, PlaylistStreamEntity.class, PlaylistRemoteEntity.class }, - version = DB_VER_15_0, + version = DB_VER_12_0, exportSchema = false ) public abstract class AppDatabase extends RoomDatabase { diff --git a/app/src/main/java/org/schabi/newpipe/database/Migrations.java b/app/src/main/java/org/schabi/newpipe/database/Migrations.java index a1a2ea31243..239fc02bbd9 100644 --- a/app/src/main/java/org/schabi/newpipe/database/Migrations.java +++ b/app/src/main/java/org/schabi/newpipe/database/Migrations.java @@ -8,7 +8,6 @@ public class Migrations { public static final int DB_VER_11_0 = 1; public static final int DB_VER_12_0 = 2; - public static final int DB_VER_15_0 = 3; public static final Migration MIGRATION_11_12 = new Migration(DB_VER_11_0, DB_VER_12_0) { @Override @@ -59,11 +58,4 @@ public void migrate(@NonNull SupportSQLiteDatabase database) { database.execSQL("DROP TABLE IF EXISTS watch_history"); } }; - - public static final Migration MIGRATION_12_15 = new Migration(DB_VER_12_0, DB_VER_15_0) { - @Override - public void migrate(@NonNull SupportSQLiteDatabase database) { - database.execSQL("ALTER TABLE `stream_history` ADD COLUMN `position` INTEGER DEFAULT 0"); - } - }; } diff --git a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java index 37a0ccd0039..b553f437d8c 100644 --- a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java +++ b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java @@ -31,7 +31,6 @@ public class StreamHistoryEntity { final public static String JOIN_STREAM_ID = "stream_id"; final public static String STREAM_ACCESS_DATE = "access_date"; final public static String STREAM_REPEAT_COUNT = "repeat_count"; - final public static String STREAM_POSITION = "position"; @ColumnInfo(name = JOIN_STREAM_ID) private long streamUid; @@ -43,19 +42,15 @@ public class StreamHistoryEntity { @ColumnInfo(name = STREAM_REPEAT_COUNT) private long repeatCount; - @ColumnInfo(name = STREAM_POSITION) - private long position; - - public StreamHistoryEntity(long streamUid, @NonNull Date accessDate, long repeatCount, long position) { + public StreamHistoryEntity(long streamUid, @NonNull Date accessDate, long repeatCount) { this.streamUid = streamUid; this.accessDate = accessDate; this.repeatCount = repeatCount; - this.position = position; } @Ignore - public StreamHistoryEntity(long streamUid, @NonNull Date accessDate, long position) { - this(streamUid, accessDate, 1, position); + public StreamHistoryEntity(long streamUid, @NonNull Date accessDate) { + this(streamUid, accessDate, 1); } public long getStreamUid() { @@ -81,12 +76,4 @@ public long getRepeatCount() { public void setRepeatCount(long repeatCount) { this.repeatCount = repeatCount; } - - public long getPosition() { - return position; - } - - public void setPosition(long position) { - this.position = position; - } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 04af024d44c..a869f24efdd 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -1348,11 +1348,11 @@ private void updatePositionInfo(final StreamInfo info) { if (recordManager == null) { recordManager = new HistoryRecordManager(requireContext()); } - disposables.add(recordManager.getStreamHistory(info).onErrorComplete() + disposables.add(recordManager.loadStreamState(info).onErrorComplete() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()).subscribe( - history -> { - final int seconds = (int) (history.getPosition() / 1000.f); + state -> { + final int seconds = (int) (state.getProgressTime() / 1000.f); if (seconds < info.getDuration() - Constants.SECONDS_MIN_LEFT) { positionView.setMax((int) info.getDuration()); positionView.setProgress(seconds); diff --git a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java index 3c42a04d3ed..71c5ae0f52f 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java @@ -75,29 +75,20 @@ public HistoryRecordManager(final Context context) { /////////////////////////////////////////////////////// public Maybe onViewed(final StreamInfo info) { - return onViewed(info, -1); - } - - public Maybe onViewed(final StreamInfo info, final long position) { if (!isStreamHistoryEnabled()) return Maybe.empty(); final Date currentTime = new Date(); return Maybe.fromCallable(() -> database.runInTransaction(() -> { final long streamId = streamTable.upsert(new StreamEntity(info)); - StreamHistoryEntity latestEntry = streamHistoryTable.getLatestEntry(streamId); + StreamHistoryEntity latestEntry = streamHistoryTable.getLatestEntry(); - if (latestEntry != null) { + if (latestEntry != null && latestEntry.getStreamUid() == streamId) { streamHistoryTable.delete(latestEntry); latestEntry.setAccessDate(currentTime); - if (position == -1) { - latestEntry.setRepeatCount(latestEntry.getRepeatCount() + 1); - } else { - latestEntry.setPosition(position); - } + latestEntry.setRepeatCount(latestEntry.getRepeatCount() + 1); return streamHistoryTable.insert(latestEntry); } else { - return streamHistoryTable.insert(new StreamHistoryEntity(streamId, currentTime, - position == -1 ? 0 : position)); + return streamHistoryTable.insert(new StreamHistoryEntity(streamId, currentTime)); } })).subscribeOn(Schedulers.io()); } @@ -116,7 +107,6 @@ public Flowable> getStreamHistory() { return streamHistoryTable.getHistory().subscribeOn(Schedulers.io()); } - public Maybe getStreamHistory(final StreamInfo info) { return Maybe.fromCallable(() -> { final long streamId = streamTable.upsert(new StreamEntity(info)); diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java index c96f27ee9a2..91faa101456 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -145,7 +145,6 @@ private void onClose() { lockManager.releaseWifiAndCpu(); } if (basePlayerImpl != null) { - basePlayerImpl.saveCurrentPosition(); basePlayerImpl.stopActivityBinding(); basePlayerImpl.destroy(); } diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index e1e76a4dd66..5767fb2e0ae 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -19,7 +19,6 @@ package org.schabi.newpipe.player; -import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -878,21 +877,22 @@ public void onPrepared(final boolean playWhenReady) { if (DEBUG) Log.d(TAG, "onPrepared() called with: playWhenReady = [" + playWhenReady + "]"); if (playWhenReady) audioReactor.requestAudioFocus(); if (isPlaybackResumeEnabled() && currentMetadata != null) { - final Disposable d = recordManager.getStreamHistory(currentMetadata.getMetadata()) + final Disposable d = recordManager.loadStreamState(currentMetadata.getMetadata()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( - history -> { - if (history.getPosition() > 0 && - history.getPosition() < simpleExoPlayer.getDuration() - Constants.SECONDS_MIN_LEFT * 1000) { - seekTo(history.getPosition()); - onPositionRestored(history.getPosition()); + state -> { + if (state.getProgressTime() > 0 && + state.getProgressTime() < simpleExoPlayer.getDuration() - Constants.SECONDS_MIN_LEFT * 1000) { + seekTo(state.getProgressTime()); + onPositionRestored(state.getProgressTime()); } changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); }, error -> { Log.e(TAG, "Player resume failure: ", error); changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); - } + }, + () -> changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED) ); databaseUpdateReactor.add(d); } else { @@ -1045,7 +1045,7 @@ protected void savePlaybackState(final StreamInfo info, final long progress) { databaseUpdateReactor.add(stateSaver); } - private void savePlaybackState() { + protected void savePlaybackState() { if (simpleExoPlayer == null || currentMetadata == null) return; final StreamInfo currentInfo = currentMetadata.getMetadata(); @@ -1242,19 +1242,6 @@ public boolean gotDestroyed() { return simpleExoPlayer == null; } - @SuppressWarnings("ResultOfMethodCallIgnored") - @SuppressLint("CheckResult") - public void saveCurrentPosition() { - if (currentMetadata == null) return; - final StreamInfo currentInfo = currentMetadata.getMetadata(); - final long currentPosition = simpleExoPlayer.getCurrentPosition(); - recordManager.onViewed(currentInfo, currentPosition).onErrorComplete() - .subscribe( - ignored -> {/* successful */}, - error -> Log.e(TAG, "Player onViewed() failure: ", error) - ); - } - private boolean isPlaybackResumeEnabled() { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); return prefs.getBoolean(context.getString(R.string.enable_watch_history_key), true) diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index 99a804a44ce..ff37a34ccf0 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -225,7 +225,7 @@ protected void onSaveInstanceState(Bundle outState) { @Override protected void onPause() { - playerImpl.saveCurrentPosition(); + playerImpl.savePlaybackState(); super.onPause(); } diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index 291132275ae..f5c731ed9cf 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -323,7 +323,6 @@ public void closePopup() { if (playerImpl.getRootView() != null) { windowManager.removeView(playerImpl.getRootView()); } - playerImpl.saveCurrentPosition(); playerImpl.setRootView(null); playerImpl.stopActivityBinding(); playerImpl.destroy(); From 40570f7a6c46c73f359bf393ad53a0eb38df22da Mon Sep 17 00:00:00 2001 From: Vasiliy Date: Wed, 27 Feb 2019 18:37:43 +0200 Subject: [PATCH 11/22] Refactor: threshold constant --- .../schabi/newpipe/fragments/detail/VideoDetailFragment.java | 5 ++--- app/src/main/java/org/schabi/newpipe/player/BasePlayer.java | 5 +++-- app/src/main/java/org/schabi/newpipe/util/Constants.java | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 014b6f6c4c8..f0c58424f0d 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -34,14 +34,12 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewParent; import android.widget.AdapterView; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; -import android.widget.ScrollView; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; @@ -73,6 +71,7 @@ import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.local.history.HistoryRecordManager; +import org.schabi.newpipe.player.BasePlayer; import org.schabi.newpipe.player.MainVideoPlayer; import org.schabi.newpipe.player.PopupVideoPlayer; import org.schabi.newpipe.player.playqueue.PlayQueue; @@ -1265,7 +1264,7 @@ private void updatePositionInfo(final StreamInfo info) { .observeOn(AndroidSchedulers.mainThread()).subscribe( state -> { final int seconds = (int) (state.getProgressTime() / 1000.f); - if (seconds < info.getDuration() - Constants.SECONDS_MIN_LEFT) { + if (seconds < info.getDuration() - BasePlayer.PLAYBACK_SAVE_THRESHOLD_SECONDS) { positionView.setMax((int) info.getDuration()); positionView.setProgress(seconds); detailPositionView.setText(Localization.getDurationString(seconds)); diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index 5767fb2e0ae..e65621a0cde 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -72,7 +72,6 @@ import org.schabi.newpipe.player.playqueue.PlayQueueAdapter; import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.resolver.MediaSourceTag; -import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.SerializedCache; @@ -180,6 +179,8 @@ public abstract class BasePlayer implements protected final static int PLAY_PREV_ACTIVATION_LIMIT_MILLIS = 5000; // 5 seconds protected final static int PROGRESS_LOOP_INTERVAL_MILLIS = 500; protected final static int RECOVERY_SKIP_THRESHOLD_MILLIS = 3000; // 3 seconds + /** Playback state will not be saved, if time left less than this threshold */ + public static final int PLAYBACK_SAVE_THRESHOLD_SECONDS = 10; protected SimpleExoPlayer simpleExoPlayer; protected AudioReactor audioReactor; @@ -882,7 +883,7 @@ public void onPrepared(final boolean playWhenReady) { .subscribe( state -> { if (state.getProgressTime() > 0 && - state.getProgressTime() < simpleExoPlayer.getDuration() - Constants.SECONDS_MIN_LEFT * 1000) { + state.getProgressTime() < simpleExoPlayer.getDuration() - PLAYBACK_SAVE_THRESHOLD_SECONDS * 1000) { seekTo(state.getProgressTime()); onPositionRestored(state.getProgressTime()); } diff --git a/app/src/main/java/org/schabi/newpipe/util/Constants.java b/app/src/main/java/org/schabi/newpipe/util/Constants.java index 5396b4d84c7..b01b6df6abd 100644 --- a/app/src/main/java/org/schabi/newpipe/util/Constants.java +++ b/app/src/main/java/org/schabi/newpipe/util/Constants.java @@ -12,6 +12,4 @@ public class Constants { public static final String KEY_MAIN_PAGE_CHANGE = "key_main_page_change"; public static final int NO_SERVICE_ID = -1; - - public static final int SECONDS_MIN_LEFT = 10; } From e482b689ccc2187f5f6626fd5008d10fd57b727e Mon Sep 17 00:00:00 2001 From: Vasiliy Date: Tue, 5 Mar 2019 14:28:35 +0200 Subject: [PATCH 12/22] Fixes --- .../fragments/detail/VideoDetailFragment.java | 34 +++++----- app/src/main/res/xml/history_settings.xml | 66 ++++++++++--------- 2 files changed, 51 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 61d71ce9241..819f6884987 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -1268,22 +1268,22 @@ private void updatePositionInfo(final StreamInfo info) { disposables.add(recordManager.loadStreamState(info).onErrorComplete() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()).subscribe( - state -> { - final int seconds = (int) (state.getProgressTime() / 1000.f); - if (seconds < info.getDuration() - BasePlayer.PLAYBACK_SAVE_THRESHOLD_SECONDS) { - positionView.setMax((int) info.getDuration()); - positionView.setProgress(seconds); - detailPositionView.setText(Localization.getDurationString(seconds)); - animateView(positionView, true, 500); - animateView(detailPositionView, true, 500); - } else { - animateView(positionView, false, 500); - animateView(detailPositionView, false, 500); - } - }, - error -> { - Log.e(TAG, "Player resume failure: ", error); - } - )); + state -> { + final int seconds = (int) (state.getProgressTime() / 1000.f); + if (seconds < info.getDuration() - BasePlayer.PLAYBACK_SAVE_THRESHOLD_SECONDS) { + positionView.setMax((int) info.getDuration()); + positionView.setProgress(seconds); + detailPositionView.setText(Localization.getDurationString(seconds)); + animateView(positionView, true, 500); + animateView(detailPositionView, true, 500); + } else { + animateView(positionView, false, 500); + animateView(detailPositionView, false, 500); + } + }, + error -> { + Log.e(TAG, "Player resume failure: ", error); + } + )); } } diff --git a/app/src/main/res/xml/history_settings.xml b/app/src/main/res/xml/history_settings.xml index 15ecffcf195..c78f98c0e86 100644 --- a/app/src/main/res/xml/history_settings.xml +++ b/app/src/main/res/xml/history_settings.xml @@ -1,49 +1,51 @@ - + android:title="@string/enable_watch_history_title" + app:iconSpaceReserved="false" /> - + - - - - - - ->>>>>>> dev + android:title="@string/enable_search_history_title" + app:iconSpaceReserved="false" /> + + + + + + + + + + From 7464362ad1409a5886f1f70a7fc289c98a02d557 Mon Sep 17 00:00:00 2001 From: Vasiliy Date: Tue, 5 Mar 2019 14:35:58 +0200 Subject: [PATCH 13/22] Save playback state in popup player --- .../main/java/org/schabi/newpipe/player/PopupVideoPlayer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index 7578c444c92..2be298713f7 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -325,6 +325,7 @@ public void closePopup() { isPopupClosing = true; if (playerImpl != null) { + playerImpl.savePlaybackState(); if (playerImpl.getRootView() != null) { windowManager.removeView(playerImpl.getRootView()); } From dd8899067bedb41627dfb862dbdb912b8cdd28af Mon Sep 17 00:00:00 2001 From: Vasiliy Date: Tue, 5 Mar 2019 14:38:04 +0200 Subject: [PATCH 14/22] Save playback state in background player --- .../main/java/org/schabi/newpipe/player/BackgroundPlayer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java index 94b401f0963..d1a4ddaf987 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -150,6 +150,7 @@ private void onClose() { lockManager.releaseWifiAndCpu(); } if (basePlayerImpl != null) { + basePlayerImpl.savePlaybackState(); basePlayerImpl.stopActivityBinding(); basePlayerImpl.destroy(); } From f10ebc82ededcd9f10d1ca8710117ddb42828641 Mon Sep 17 00:00:00 2001 From: Vasily Date: Wed, 6 Mar 2019 11:42:34 +0200 Subject: [PATCH 15/22] Fix playback save thresholds --- .../fragments/detail/VideoDetailFragment.java | 3 ++- .../org/schabi/newpipe/player/BasePlayer.java | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 819f6884987..27df098460d 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -1270,7 +1270,8 @@ private void updatePositionInfo(final StreamInfo info) { .observeOn(AndroidSchedulers.mainThread()).subscribe( state -> { final int seconds = (int) (state.getProgressTime() / 1000.f); - if (seconds < info.getDuration() - BasePlayer.PLAYBACK_SAVE_THRESHOLD_SECONDS) { + if (seconds > BasePlayer.PLAYBACK_SAVE_THRESHOLD_START_SECONDS && + seconds < info.getDuration() - BasePlayer.PLAYBACK_SAVE_THRESHOLD_END_SECONDS) { positionView.setMax((int) info.getDuration()); positionView.setProgress(seconds); detailPositionView.setText(Localization.getDurationString(seconds)); diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index e65621a0cde..b154fd60d58 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -178,9 +178,12 @@ public abstract class BasePlayer implements protected final static int FAST_FORWARD_REWIND_AMOUNT_MILLIS = 10000; // 10 Seconds protected final static int PLAY_PREV_ACTIVATION_LIMIT_MILLIS = 5000; // 5 seconds protected final static int PROGRESS_LOOP_INTERVAL_MILLIS = 500; - protected final static int RECOVERY_SKIP_THRESHOLD_MILLIS = 3000; // 3 seconds + /** Playback state will not be saved, if playback time less than this threshold */ + public static final int PLAYBACK_SAVE_THRESHOLD_START_SECONDS = 5; + public static final long PLAYBACK_SAVE_THRESHOLD_START_MILLIS = TimeUnit.SECONDS.toMillis(PLAYBACK_SAVE_THRESHOLD_START_SECONDS); /** Playback state will not be saved, if time left less than this threshold */ - public static final int PLAYBACK_SAVE_THRESHOLD_SECONDS = 10; + public static final int PLAYBACK_SAVE_THRESHOLD_END_SECONDS = 10; + public static final long PLAYBACK_SAVE_THRESHOLD_END_MILLIS = TimeUnit.SECONDS.toMillis(PLAYBACK_SAVE_THRESHOLD_END_SECONDS); protected SimpleExoPlayer simpleExoPlayer; protected AudioReactor audioReactor; @@ -882,8 +885,8 @@ public void onPrepared(final boolean playWhenReady) { .observeOn(AndroidSchedulers.mainThread()) .subscribe( state -> { - if (state.getProgressTime() > 0 && - state.getProgressTime() < simpleExoPlayer.getDuration() - PLAYBACK_SAVE_THRESHOLD_SECONDS * 1000) { + if (state.getProgressTime() > PLAYBACK_SAVE_THRESHOLD_START_MILLIS && + state.getProgressTime() < simpleExoPlayer.getDuration() - PLAYBACK_SAVE_THRESHOLD_END_MILLIS) { seekTo(state.getProgressTime()); onPositionRestored(state.getProgressTime()); } @@ -1050,9 +1053,9 @@ protected void savePlaybackState() { if (simpleExoPlayer == null || currentMetadata == null) return; final StreamInfo currentInfo = currentMetadata.getMetadata(); - if (simpleExoPlayer.getCurrentPosition() > RECOVERY_SKIP_THRESHOLD_MILLIS && + if (simpleExoPlayer.getCurrentPosition() > PLAYBACK_SAVE_THRESHOLD_START_MILLIS && simpleExoPlayer.getCurrentPosition() < - simpleExoPlayer.getDuration() - RECOVERY_SKIP_THRESHOLD_MILLIS) { + simpleExoPlayer.getDuration() - PLAYBACK_SAVE_THRESHOLD_END_MILLIS) { savePlaybackState(currentInfo, simpleExoPlayer.getCurrentPosition()); } } From 26772980c1909ccaa8c16842a4f4284ee7858d92 Mon Sep 17 00:00:00 2001 From: Vasily Date: Wed, 6 Mar 2019 11:56:45 +0200 Subject: [PATCH 16/22] Remove playback state on finishing stream --- .../fragments/detail/VideoDetailFragment.java | 4 +++ .../local/history/HistoryRecordManager.java | 7 +++++ .../org/schabi/newpipe/player/BasePlayer.java | 26 +++++++++++++++---- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 27df098460d..fb2feceedb6 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -1284,6 +1284,10 @@ private void updatePositionInfo(final StreamInfo info) { }, error -> { Log.e(TAG, "Player resume failure: ", error); + }, + () -> { + animateView(positionView, false, 500); + animateView(detailPositionView, false, 500); } )); } diff --git a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java index 71c5ae0f52f..e762a70651e 100644 --- a/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java +++ b/app/src/main/java/org/schabi/newpipe/local/history/HistoryRecordManager.java @@ -202,6 +202,13 @@ public Maybe saveStreamState(@NonNull final StreamInfo info, final long pr })).subscribeOn(Schedulers.io()); } + public Maybe resetStreamState(@NonNull final StreamInfo info) { + return Maybe.fromCallable(() -> database.runInTransaction(() -> { + final long streamId = streamTable.upsert(new StreamEntity(info)); + return streamStateTable.deleteState(streamId); + })).subscribeOn(Schedulers.io()); + } + /////////////////////////////////////////////////////// // Utility /////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index b154fd60d58..c237bc21d0b 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -886,7 +886,8 @@ public void onPrepared(final boolean playWhenReady) { .subscribe( state -> { if (state.getProgressTime() > PLAYBACK_SAVE_THRESHOLD_START_MILLIS && - state.getProgressTime() < simpleExoPlayer.getDuration() - PLAYBACK_SAVE_THRESHOLD_END_MILLIS) { + state.getProgressTime() < simpleExoPlayer.getDuration() - + PLAYBACK_SAVE_THRESHOLD_END_MILLIS) { seekTo(state.getProgressTime()); onPositionRestored(state.getProgressTime()); } @@ -1049,14 +1050,29 @@ protected void savePlaybackState(final StreamInfo info, final long progress) { databaseUpdateReactor.add(stateSaver); } + protected void resetPlaybackState(final StreamInfo info) { + if (info == null) return; + final Disposable d = recordManager.resetStreamState(info) + .observeOn(AndroidSchedulers.mainThread()) + .onErrorComplete() + .subscribe( + ignored -> {/* successful */}, + error -> Log.e(TAG, "savePlaybackState() failure: ", error) + ); + databaseUpdateReactor.add(d); + } + protected void savePlaybackState() { if (simpleExoPlayer == null || currentMetadata == null) return; final StreamInfo currentInfo = currentMetadata.getMetadata(); - if (simpleExoPlayer.getCurrentPosition() > PLAYBACK_SAVE_THRESHOLD_START_MILLIS && - simpleExoPlayer.getCurrentPosition() < - simpleExoPlayer.getDuration() - PLAYBACK_SAVE_THRESHOLD_END_MILLIS) { - savePlaybackState(currentInfo, simpleExoPlayer.getCurrentPosition()); + if (simpleExoPlayer.getCurrentPosition() > PLAYBACK_SAVE_THRESHOLD_START_MILLIS) { + if (simpleExoPlayer.getCurrentPosition() < simpleExoPlayer.getDuration() - + PLAYBACK_SAVE_THRESHOLD_END_MILLIS) { + savePlaybackState(currentInfo, simpleExoPlayer.getCurrentPosition()); + } else { + resetPlaybackState(currentInfo); + } } } From 32696925b818470077d526e17739e013e77bd6b0 Mon Sep 17 00:00:00 2001 From: Vasily Date: Wed, 6 Mar 2019 12:10:32 +0200 Subject: [PATCH 17/22] Save playback state on change quality --- app/src/main/java/org/schabi/newpipe/player/BasePlayer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index c237bc21d0b..ac8b3a5c6e3 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -1029,6 +1029,7 @@ private void registerView() { } protected void reload() { + savePlaybackState(); if (playbackManager != null) { playbackManager.dispose(); } From 3cbc84d906c472272c3aa4698126277a83f774a7 Mon Sep 17 00:00:00 2001 From: Vasily Date: Wed, 6 Mar 2019 12:21:58 +0200 Subject: [PATCH 18/22] Fix settings layout --- app/src/main/res/xml/history_settings.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/xml/history_settings.xml b/app/src/main/res/xml/history_settings.xml index c78f98c0e86..db8fc36de6b 100644 --- a/app/src/main/res/xml/history_settings.xml +++ b/app/src/main/res/xml/history_settings.xml @@ -26,7 +26,10 @@ android:title="@string/enable_search_history_title" app:iconSpaceReserved="false" /> - + Date: Mon, 11 Mar 2019 17:04:21 +0200 Subject: [PATCH 19/22] Reset playback state on playing complete --- .../fragments/detail/VideoDetailFragment.java | 10 ++++++-- .../newpipe/player/BackgroundPlayer.java | 1 - .../org/schabi/newpipe/player/BasePlayer.java | 24 +++++++++++++++---- .../newpipe/player/MainVideoPlayer.java | 6 ----- .../newpipe/player/PopupVideoPlayer.java | 1 - .../schabi/newpipe/player/VideoPlayer.java | 1 + 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index fb2feceedb6..403685a78ef 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -50,6 +50,8 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.ReCaptchaActivity; +import org.schabi.newpipe.database.stream.model.StreamEntity; +import org.schabi.newpipe.database.stream.model.StreamStateEntity; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.NewPipe; @@ -96,6 +98,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.TimeUnit; import icepick.State; import io.reactivex.Single; @@ -1265,9 +1268,12 @@ private void updatePositionInfo(final StreamInfo info) { if (recordManager == null) { recordManager = new HistoryRecordManager(requireContext()); } - disposables.add(recordManager.loadStreamState(info).onErrorComplete() + disposables.add(recordManager.loadStreamState(info) + .onErrorComplete() .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()).subscribe( + .delaySubscription(500, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( state -> { final int seconds = (int) (state.getProgressTime() / 1000.f); if (seconds > BasePlayer.PLAYBACK_SAVE_THRESHOLD_START_SECONDS && diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java index c954885419f..3989581fdd3 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -150,7 +150,6 @@ private void onClose() { lockManager.releaseWifiAndCpu(); } if (basePlayerImpl != null) { - basePlayerImpl.savePlaybackState(); basePlayerImpl.stopActivityBinding(); basePlayerImpl.destroy(); } diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index ac8b3a5c6e3..57fb0c22347 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -28,6 +28,7 @@ import android.graphics.BitmapFactory; import android.media.AudioManager; import android.preference.PreferenceManager; +import android.support.annotation.CallSuper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; @@ -323,6 +324,7 @@ public void destroyPlayer() { public void destroy() { if (DEBUG) Log.d(TAG, "destroy() called"); + savePlaybackState(); destroyPlayer(); unregisterBroadcastReceiver(); @@ -421,6 +423,7 @@ protected void unregisterBroadcastReceiver() { protected int currentState = STATE_PREFLIGHT; + @CallSuper public void changeState(int state) { if (DEBUG) Log.d(TAG, "changeState() called with: state = [" + state + "]"); currentState = state; @@ -446,11 +449,13 @@ public void changeState(int state) { } } + @CallSuper public void onBlocked() { if (DEBUG) Log.d(TAG, "onBlocked() called"); if (!isProgressLoopRunning()) startProgressLoop(); } + @CallSuper public void onPlaying() { if (DEBUG) Log.d(TAG, "onPlaying() called"); if (!isProgressLoopRunning()) startProgressLoop(); @@ -459,15 +464,24 @@ public void onPlaying() { public void onBuffering() { } + @CallSuper public void onPaused() { - if (isProgressLoopRunning()) stopProgressLoop(); + if (isProgressLoopRunning()) { + stopProgressLoop(); + } else { + savePlaybackState(); + } } public void onPausedSeek() { } + @CallSuper public void onCompleted() { if (DEBUG) Log.d(TAG, "onCompleted() called"); + if (currentMetadata != null) { + resetPlaybackState(currentMetadata.getMetadata()); + } if (playQueue.getIndex() < playQueue.size() - 1) playQueue.offsetIndex(+1); if (isProgressLoopRunning()) stopProgressLoop(); } @@ -1039,8 +1053,9 @@ protected void reload() { } } - protected void savePlaybackState(final StreamInfo info, final long progress) { + private void savePlaybackState(final StreamInfo info, final long progress) { if (info == null) return; + Log.d(TAG, "savePlaybackState() called"); final Disposable stateSaver = recordManager.saveStreamState(info, progress) .observeOn(AndroidSchedulers.mainThread()) .onErrorComplete() @@ -1051,14 +1066,15 @@ protected void savePlaybackState(final StreamInfo info, final long progress) { databaseUpdateReactor.add(stateSaver); } - protected void resetPlaybackState(final StreamInfo info) { + private void resetPlaybackState(final StreamInfo info) { if (info == null) return; + Log.d(TAG, "resetPlaybackState() called"); final Disposable d = recordManager.resetStreamState(info) .observeOn(AndroidSchedulers.mainThread()) .onErrorComplete() .subscribe( ignored -> {/* successful */}, - error -> Log.e(TAG, "savePlaybackState() failure: ", error) + error -> Log.e(TAG, "resetPlaybackState() failure: ", error) ); databaseUpdateReactor.add(d); } diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index ad22dcde680..a5125277e4b 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -223,12 +223,6 @@ protected void onSaveInstanceState(Bundle outState) { StateSaver.tryToSave(isChangingConfigurations(), null, outState, this); } - @Override - protected void onPause() { - playerImpl.savePlaybackState(); - super.onPause(); - } - @Override protected void onStop() { if (DEBUG) Log.d(TAG, "onStop() called"); diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index 2be298713f7..7578c444c92 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -325,7 +325,6 @@ public void closePopup() { isPopupClosing = true; if (playerImpl != null) { - playerImpl.savePlaybackState(); if (playerImpl.getRootView() != null) { windowManager.removeView(playerImpl.getRootView()); } diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index 7971e33909f..05e6732a9fd 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -431,6 +431,7 @@ public void onBuffering() { @Override public void onPaused() { + super.onPaused(); if (DEBUG) Log.d(TAG, "onPaused() called"); showControls(400); loadingPanel.setVisibility(View.GONE); From 06cf59f350831d18150b09e272a1beedd4edf678 Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 12 Mar 2019 09:40:37 +0200 Subject: [PATCH 20/22] Fix logging --- .../fragments/detail/VideoDetailFragment.java | 22 ++++++---- .../org/schabi/newpipe/player/BasePlayer.java | 41 ++++++++++++------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 403685a78ef..d6fdaec3b9a 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -291,10 +291,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { case ReCaptchaActivity.RECAPTCHA_REQUEST: if (resultCode == Activity.RESULT_OK) { NavigationHelper.openVideoDetailFragment(getFragmentManager(), serviceId, url, name); - } else Log.e(TAG, "ReCaptcha failed"); + } else if (DEBUG) Log.e(TAG, "ReCaptcha failed"); break; default: - Log.e(TAG, "Request code from activity not supported [" + requestCode + "]"); + if (DEBUG) Log.e(TAG, "Request code from activity not supported [" + requestCode + "]"); break; } } @@ -387,7 +387,7 @@ public void onClick(View v) { break; case R.id.detail_uploader_root_layout: if (TextUtils.isEmpty(currentInfo.getUploaderUrl())) { - Log.w(TAG, "Can't open channel because we got no channel URL"); + if (DEBUG) Log.w(TAG, "Can't open channel because we got no channel URL"); } else { try { NavigationHelper.openChannelFragment( @@ -676,8 +676,10 @@ private static void showInstallKoreDialog(final Context context) { } private void setupActionBarOnError(final String url) { - if (DEBUG) Log.d(TAG, "setupActionBarHandlerOnError() called with: url = [" + url + "]"); - Log.e("-----", "missing code"); + if (DEBUG) { + Log.d(TAG, "setupActionBarHandlerOnError() called with: url = [" + url + "]"); + Log.e("-----", "missing code"); + } } private void setupActionBar(final StreamInfo info) { @@ -728,10 +730,10 @@ public void pushToStack(int serviceId, String videoUrl, String name) { if (stack.size() > 0 && stack.peek().getServiceId() == serviceId && stack.peek().getUrl().equals(videoUrl)) { - Log.d(TAG, "pushToStack() called with: serviceId == peek.serviceId = [" + if (DEBUG) Log.d(TAG, "pushToStack() called with: serviceId == peek.serviceId = [" + serviceId + "], videoUrl == peek.getUrl = [" + videoUrl + "]"); return; - } else { + } else if (DEBUG) { Log.d(TAG, "pushToStack() wasn't equal"); } @@ -949,7 +951,9 @@ private void startOnExternalPlayer(@NonNull final Context context, disposables.add(recordManager.onViewed(info).onErrorComplete() .subscribe( ignored -> {/* successful */}, - error -> Log.e(TAG, "Register view failure: ", error) + error -> { + if (DEBUG) Log.e(TAG, "Register view failure: ", error); + } )); } @@ -1289,7 +1293,7 @@ private void updatePositionInfo(final StreamInfo info) { } }, error -> { - Log.e(TAG, "Player resume failure: ", error); + if (DEBUG) Log.e(TAG, "Player resume failure: ", error); }, () -> { animateView(positionView, false, 500); diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index 57fb0c22347..643336c4540 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -100,7 +100,9 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListener, ImageLoadingListener { + @SuppressWarnings("ConstantConditions") public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release"); + @NonNull public static final String TAG = "BasePlayer"; @@ -353,7 +355,7 @@ public void onLoadingStarted(String imageUri, View view) { @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) { - Log.e(TAG, "Thumbnail - onLoadingFailed() called on imageUri = [" + imageUri + "]", + if (DEBUG) Log.e(TAG, "Thumbnail - onLoadingFailed() called on imageUri = [" + imageUri + "]", failReason.getCause()); currentThumbnail = null; } @@ -388,6 +390,7 @@ protected void setupBroadcastReceiver(IntentFilter intentFilter) { public void onBroadcastReceived(Intent intent) { if (intent == null || intent.getAction() == null) return; + //noinspection SwitchStatementWithTooFewBranches switch (intent.getAction()) { case AudioManager.ACTION_AUDIO_BECOMING_NOISY: onPause(); @@ -405,7 +408,7 @@ protected void unregisterBroadcastReceiver() { try { context.unregisterReceiver(broadcastReceiver); } catch (final IllegalArgumentException unregisteredException) { - Log.w(TAG, "Broadcast receiver already unregistered (" + unregisteredException.getMessage() + ")"); + if (DEBUG) Log.w(TAG, "Broadcast receiver already unregistered (" + unregisteredException.getMessage() + ")"); } } @@ -546,7 +549,9 @@ private Disposable getProgressReactor() { return Observable.interval(PROGRESS_LOOP_INTERVAL_MILLIS, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe(ignored -> triggerProgressUpdate(), - error -> Log.e(TAG, "Progress update failure: ", error)); + error -> { + if (DEBUG) Log.e(TAG, "Progress update failure: ", error); + }); } /*////////////////////////////////////////////////////////////////////////// @@ -817,14 +822,14 @@ public void onPlaybackSynchronize(@NonNull final PlayQueueItem item) { // Check if on wrong window if (currentPlayQueueIndex != playQueue.getIndex()) { - Log.e(TAG, "Playback - Play Queue may be desynchronized: item " + + if (DEBUG) Log.e(TAG, "Playback - Play Queue may be desynchronized: item " + "index=[" + currentPlayQueueIndex + "], " + "queue index=[" + playQueue.getIndex() + "]"); // Check if bad seek position } else if ((currentPlaylistSize > 0 && currentPlayQueueIndex >= currentPlaylistSize) || currentPlayQueueIndex < 0) { - Log.e(TAG, "Playback - Trying to seek to invalid " + + if (DEBUG) Log.e(TAG, "Playback - Trying to seek to invalid " + "index=[" + currentPlayQueueIndex + "] with " + "playlist length=[" + currentPlaylistSize + "]"); @@ -908,7 +913,7 @@ public void onPrepared(final boolean playWhenReady) { changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); }, error -> { - Log.e(TAG, "Player resume failure: ", error); + if (DEBUG) Log.e(TAG, "Player resume failure: ", error); changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); }, () -> changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED) @@ -1037,7 +1042,9 @@ private void registerView() { final Disposable viewRegister = recordManager.onViewed(currentInfo).onErrorComplete() .subscribe( ignored -> {/* successful */}, - error -> Log.e(TAG, "Player onViewed() failure: ", error) + error -> { + if (DEBUG) Log.e(TAG, "Player onViewed() failure: ", error); + } ); databaseUpdateReactor.add(viewRegister); } @@ -1055,26 +1062,30 @@ protected void reload() { private void savePlaybackState(final StreamInfo info, final long progress) { if (info == null) return; - Log.d(TAG, "savePlaybackState() called"); + if (DEBUG) Log.d(TAG, "savePlaybackState() called"); final Disposable stateSaver = recordManager.saveStreamState(info, progress) .observeOn(AndroidSchedulers.mainThread()) .onErrorComplete() .subscribe( ignored -> {/* successful */}, - error -> Log.e(TAG, "savePlaybackState() failure: ", error) + error -> { + if (DEBUG) Log.e(TAG, "savePlaybackState() failure: ", error); + } ); databaseUpdateReactor.add(stateSaver); } private void resetPlaybackState(final StreamInfo info) { if (info == null) return; - Log.d(TAG, "resetPlaybackState() called"); + if (DEBUG) Log.d(TAG, "resetPlaybackState() called"); final Disposable d = recordManager.resetStreamState(info) .observeOn(AndroidSchedulers.mainThread()) .onErrorComplete() .subscribe( ignored -> {/* successful */}, - error -> Log.e(TAG, "resetPlaybackState() failure: ", error) + error -> { + if (DEBUG) Log.e(TAG, "resetPlaybackState() failure: ", error); + } ); databaseUpdateReactor.add(d); } @@ -1188,11 +1199,13 @@ public boolean isLive() { if (simpleExoPlayer == null) return false; try { return simpleExoPlayer.isCurrentWindowDynamic(); - } catch (@NonNull IndexOutOfBoundsException ignored) { + } catch (@NonNull IndexOutOfBoundsException e) { // Why would this even happen =( // But lets log it anyway. Save is save - if (DEBUG) Log.d(TAG, "Could not update metadata: " + ignored.getMessage()); - if (DEBUG) ignored.printStackTrace(); + if (DEBUG) { + Log.d(TAG, "Could not update metadata: " + e.getMessage()); + e.printStackTrace(); + } return false; } } From 393cea9163227e6cb83aaca2c0bd1849b0fe8503 Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 12 Mar 2019 10:25:19 +0200 Subject: [PATCH 21/22] Fix playback state saving again --- .../fragments/detail/VideoDetailFragment.java | 1 - .../newpipe/player/BackgroundPlayer.java | 1 + .../org/schabi/newpipe/player/BasePlayer.java | 46 ++++++++----------- .../newpipe/player/MainVideoPlayer.java | 6 +++ .../newpipe/player/PopupVideoPlayer.java | 1 + 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index d6fdaec3b9a..d4ec9006c92 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -1275,7 +1275,6 @@ private void updatePositionInfo(final StreamInfo info) { disposables.add(recordManager.loadStreamState(info) .onErrorComplete() .subscribeOn(Schedulers.io()) - .delaySubscription(500, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe( state -> { diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java index 3989581fdd3..c954885419f 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -150,6 +150,7 @@ private void onClose() { lockManager.releaseWifiAndCpu(); } if (basePlayerImpl != null) { + basePlayerImpl.savePlaybackState(); basePlayerImpl.stopActivityBinding(); basePlayerImpl.destroy(); } diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index 643336c4540..f72e04b8be4 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -326,7 +326,6 @@ public void destroyPlayer() { public void destroy() { if (DEBUG) Log.d(TAG, "destroy() called"); - savePlaybackState(); destroyPlayer(); unregisterBroadcastReceiver(); @@ -620,9 +619,9 @@ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { break; case Player.STATE_READY: //3 maybeUpdateCurrentMetadata(); - maybeCorrectSeekPosition(); if (!isPrepared) { isPrepared = true; + maybeCorrectSeekPosition(); onPrepared(playWhenReady); break; } @@ -648,6 +647,23 @@ private void maybeCorrectSeekPosition() { if (DEBUG) Log.d(TAG, "Playback - Seeking to preset start " + "position=[" + presetStartPositionMillis + "]"); seekTo(presetStartPositionMillis); + } else if (isPlaybackResumeEnabled()) { + final Disposable stateLoader = recordManager.loadStreamState(currentMetadata.getMetadata()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + state -> { + if (state.getProgressTime() > PLAYBACK_SAVE_THRESHOLD_START_MILLIS && + state.getProgressTime() < simpleExoPlayer.getDuration() - + PLAYBACK_SAVE_THRESHOLD_END_MILLIS) { + seekTo(state.getProgressTime()); + onPositionRestored(state.getProgressTime()); + } + }, + error -> { + if (DEBUG) Log.e(TAG, "Player resume failure: ", error); + } + ); + databaseUpdateReactor.add(stateLoader); } } @@ -899,29 +915,7 @@ public void showUnrecoverableError(Exception exception) { public void onPrepared(final boolean playWhenReady) { if (DEBUG) Log.d(TAG, "onPrepared() called with: playWhenReady = [" + playWhenReady + "]"); if (playWhenReady) audioReactor.requestAudioFocus(); - if (isPlaybackResumeEnabled() && currentMetadata != null) { - final Disposable d = recordManager.loadStreamState(currentMetadata.getMetadata()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - state -> { - if (state.getProgressTime() > PLAYBACK_SAVE_THRESHOLD_START_MILLIS && - state.getProgressTime() < simpleExoPlayer.getDuration() - - PLAYBACK_SAVE_THRESHOLD_END_MILLIS) { - seekTo(state.getProgressTime()); - onPositionRestored(state.getProgressTime()); - } - changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); - }, - error -> { - if (DEBUG) Log.e(TAG, "Player resume failure: ", error); - changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); - }, - () -> changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED) - ); - databaseUpdateReactor.add(d); - } else { - changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); - } + changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); } public void onPositionRestored(long position) { @@ -1090,7 +1084,7 @@ private void resetPlaybackState(final StreamInfo info) { databaseUpdateReactor.add(d); } - protected void savePlaybackState() { + public void savePlaybackState() { if (simpleExoPlayer == null || currentMetadata == null) return; final StreamInfo currentInfo = currentMetadata.getMetadata(); diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index a5125277e4b..0a7f52e3a87 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -164,6 +164,12 @@ protected void onNewIntent(Intent intent) { } } + @Override + protected void onPause() { + playerImpl.savePlaybackState(); + super.onPause(); + } + @Override protected void onResume() { if (DEBUG) Log.d(TAG, "onResume() called"); diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index 7578c444c92..2be298713f7 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -325,6 +325,7 @@ public void closePopup() { isPopupClosing = true; if (playerImpl != null) { + playerImpl.savePlaybackState(); if (playerImpl.getRootView() != null) { windowManager.removeView(playerImpl.getRootView()); } From ca103ae34549a9897ec4b9efce688b2971b3f87f Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 12 Mar 2019 11:25:34 +0200 Subject: [PATCH 22/22] Fix trouble with background player --- .../java/org/schabi/newpipe/player/BasePlayer.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index f72e04b8be4..00b57ec3a87 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -78,6 +78,7 @@ import java.io.IOException; import java.net.UnknownHostException; +import java.util.Queue; import java.util.concurrent.TimeUnit; import io.reactivex.Observable; @@ -470,9 +471,8 @@ public void onBuffering() { public void onPaused() { if (isProgressLoopRunning()) { stopProgressLoop(); - } else { - savePlaybackState(); } + savePlaybackState(); } public void onPausedSeek() { @@ -752,6 +752,9 @@ public void onPositionDiscontinuity(@Player.DiscontinuityReason final int reason case DISCONTINUITY_REASON_SEEK_ADJUSTMENT: case DISCONTINUITY_REASON_INTERNAL: if (playQueue.getIndex() != newWindowIndex) { + if (currentMetadata != null) { + resetPlaybackState(currentMetadata.getMetadata()); + } playQueue.setIndex(newWindowIndex); } break; @@ -921,6 +924,7 @@ public void onPrepared(final boolean playWhenReady) { public void onPositionRestored(long position) { } + @CallSuper public void onPlay() { if (DEBUG) Log.d(TAG, "onPlay() called"); if (audioReactor == null || playQueue == null || simpleExoPlayer == null) return; @@ -938,6 +942,7 @@ public void onPlay() { simpleExoPlayer.setPlayWhenReady(true); } + @CallSuper public void onPause() { if (DEBUG) Log.d(TAG, "onPause() called"); if (audioReactor == null || simpleExoPlayer == null) return; @@ -946,6 +951,7 @@ public void onPause() { simpleExoPlayer.setPlayWhenReady(false); } + @CallSuper public void onPlayPause() { if (DEBUG) Log.d(TAG, "onPlayPause() called"); @@ -956,16 +962,19 @@ public void onPlayPause() { } } + @CallSuper public void onFastRewind() { if (DEBUG) Log.d(TAG, "onFastRewind() called"); seekBy(-FAST_FORWARD_REWIND_AMOUNT_MILLIS); } + @CallSuper public void onFastForward() { if (DEBUG) Log.d(TAG, "onFastForward() called"); seekBy(FAST_FORWARD_REWIND_AMOUNT_MILLIS); } + @CallSuper public void onPlayPrevious() { if (simpleExoPlayer == null || playQueue == null) return; if (DEBUG) Log.d(TAG, "onPlayPrevious() called"); @@ -983,6 +992,7 @@ public void onPlayPrevious() { } } + @CallSuper public void onPlayNext() { if (playQueue == null) return; if (DEBUG) Log.d(TAG, "onPlayNext() called");