getParentActivity() {
final ViewParent rootParent = binding.getRoot().getParent();
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
index 7df9102b7..43440b873 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
@@ -8,7 +8,6 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePopupLayoutP
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
-import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -61,6 +60,12 @@ public final class PopupPlayerUi extends VideoPlayerUi {
private WindowManager.LayoutParams popupLayoutParams; // null if player is not popup
private final WindowManager windowManager;
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Constructor, setup, destroy
+ //////////////////////////////////////////////////////////////////////////*/
+ //region Constructor, setup, destroy
+
public PopupPlayerUi(@NonNull final Player player,
@NonNull final PlayerBinding playerBinding) {
super(player, playerBinding);
@@ -173,11 +178,14 @@ public final class PopupPlayerUi extends VideoPlayerUi {
super.destroy();
removePopupFromView();
}
+ //endregion
+
/*//////////////////////////////////////////////////////////////////////////
// Broadcast receiver
//////////////////////////////////////////////////////////////////////////*/
//region Broadcast receiver
+
@Override
public void onBroadcastReceived(final Intent intent) {
super.onBroadcastReceived(intent);
@@ -200,6 +208,11 @@ public final class PopupPlayerUi extends VideoPlayerUi {
//endregion
+ /*//////////////////////////////////////////////////////////////////////////
+ // Popup position and size
+ //////////////////////////////////////////////////////////////////////////*/
+ //region Popup position and size
+
/**
* Check if {@link #popupLayoutParams}' position is within a arbitrary boundary
* that goes from (0, 0) to (screenWidth, screenHeight).
@@ -272,16 +285,19 @@ public final class PopupPlayerUi extends VideoPlayerUi {
windowManager.updateViewLayout(binding.getRoot(), popupLayoutParams);
}
- private void changePopupWindowFlags(final int flags) {
- if (DEBUG) {
- Log.d(TAG, "changePopupWindowFlags() called with: flags = [" + flags + "]");
- }
-
- if (!anyPopupViewIsNull()) {
- popupLayoutParams.flags = flags;
- windowManager.updateViewLayout(binding.getRoot(), popupLayoutParams);
- }
+ @Override
+ protected float calculateMaxEndScreenThumbnailHeight(@NonNull final Bitmap bitmap) {
+ // no need for the end screen thumbnail to be resized on popup player: it's only needed
+ // for the main player so that it is enlarged correctly inside the fragment
+ return bitmap.getHeight();
}
+ //endregion
+
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Popup closing
+ //////////////////////////////////////////////////////////////////////////*/
+ //region Popup closing
public void closePopup() {
if (DEBUG) {
@@ -351,23 +367,22 @@ public final class PopupPlayerUi extends VideoPlayerUi {
}
}).start();
}
+ //endregion
- @Override
- protected float calculateMaxEndScreenThumbnailHeight(@NonNull final Bitmap bitmap) {
- // no need for the end screen thumbnail to be resized on popup player: it's only needed
- // for the main player so that it is enlarged correctly inside the fragment
- return bitmap.getHeight();
- }
+ /*//////////////////////////////////////////////////////////////////////////
+ // Playback states
+ //////////////////////////////////////////////////////////////////////////*/
+ //region Playback states
- private boolean popupHasParent() {
- return binding != null
- && binding.getRoot().getLayoutParams() instanceof WindowManager.LayoutParams
- && binding.getRoot().getParent() != null;
- }
+ private void changePopupWindowFlags(final int flags) {
+ if (DEBUG) {
+ Log.d(TAG, "changePopupWindowFlags() called with: flags = [" + flags + "]");
+ }
- private boolean anyPopupViewIsNull() {
- return popupLayoutParams == null || windowManager == null
- || binding.getRoot().getParent() == null;
+ if (!anyPopupViewIsNull()) {
+ popupLayoutParams.flags = flags;
+ windowManager.updateViewLayout(binding.getRoot(), popupLayoutParams);
+ }
}
@Override
@@ -400,11 +415,14 @@ public final class PopupPlayerUi extends VideoPlayerUi {
playbackSpeedPopupMenu.show();
isSomePopupMenuVisible = true;
}
+ //endregion
+
/*//////////////////////////////////////////////////////////////////////////
// Gestures
//////////////////////////////////////////////////////////////////////////*/
//region Gestures
+
private int distanceFromCloseButton(@NonNull final MotionEvent popupMotionEvent) {
final int closeOverlayButtonX = closeOverlayBinding.closeButton.getLeft()
+ closeOverlayBinding.closeButton.getWidth() / 2;
@@ -433,7 +451,19 @@ public final class PopupPlayerUi extends VideoPlayerUi {
/*//////////////////////////////////////////////////////////////////////////
// Getters
//////////////////////////////////////////////////////////////////////////*/
- //region Gestures
+ //region Getters
+
+ private boolean popupHasParent() {
+ return binding != null
+ && binding.getRoot().getLayoutParams() instanceof WindowManager.LayoutParams
+ && binding.getRoot().getParent() != null;
+ }
+
+ private boolean anyPopupViewIsNull() {
+ return popupLayoutParams == null || windowManager == null
+ || binding.getRoot().getParent() == null;
+ }
+
public PlayerPopupCloseOverlayBinding getCloseOverlayBinding() {
return closeOverlayBinding;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
index 24cdb8908..f4ebc3304 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
@@ -135,6 +135,12 @@ public abstract class VideoPlayerUi extends PlayerUi
@NonNull private final SeekbarPreviewThumbnailHolder seekbarPreviewThumbnailHolder =
new SeekbarPreviewThumbnailHolder();
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Constructor, setup, destroy
+ //////////////////////////////////////////////////////////////////////////*/
+ //region Constructor, setup, destroy
+
public VideoPlayerUi(@NonNull final Player player,
@NonNull final PlayerBinding playerBinding) {
super(player);
@@ -142,11 +148,6 @@ public abstract class VideoPlayerUi extends PlayerUi
setupFromView();
}
-
- /*//////////////////////////////////////////////////////////////////////////
- // Setup
- //////////////////////////////////////////////////////////////////////////*/
- //region Setup
public void setupFromView() {
initViews();
initListeners();
@@ -414,6 +415,7 @@ public abstract class VideoPlayerUi extends PlayerUi
// Broadcast receiver
//////////////////////////////////////////////////////////////////////////*/
//region Broadcast receiver
+
@Override
public void onBroadcastReceived(final Intent intent) {
super.onBroadcastReceived(intent);
@@ -433,6 +435,7 @@ public abstract class VideoPlayerUi extends PlayerUi
// Thumbnail
//////////////////////////////////////////////////////////////////////////*/
//region Thumbnail
+
/**
* Scale the player audio / end screen thumbnail down if necessary.
*
@@ -481,6 +484,7 @@ public abstract class VideoPlayerUi extends PlayerUi
// Progress loop and updates
//////////////////////////////////////////////////////////////////////////*/
//region Progress loop and updates
+
@Override
public void onUpdateProgress(final int currentProgress,
final int duration,
@@ -744,6 +748,7 @@ public abstract class VideoPlayerUi extends PlayerUi
// Playback states
//////////////////////////////////////////////////////////////////////////*/
//region Playback states
+
@Override
public void onPrepared() {
super.onPrepared();
@@ -885,7 +890,8 @@ public abstract class VideoPlayerUi extends PlayerUi
/*//////////////////////////////////////////////////////////////////////////
// Repeat, shuffle, mute
//////////////////////////////////////////////////////////////////////////*/
- //region Repeat and shuffle
+ //region Repeat, shuffle, mute
+
public void onRepeatClicked() {
if (DEBUG) {
Log.d(TAG, "onRepeatClicked() called");
@@ -945,52 +951,9 @@ public abstract class VideoPlayerUi extends PlayerUi
/*//////////////////////////////////////////////////////////////////////////
- // ExoPlayer listeners (that didn't fit in other categories)
+ // Other player listeners
//////////////////////////////////////////////////////////////////////////*/
- //region ExoPlayer listeners (that didn't fit in other categories)
- @Override
- public void onTextTracksChanged(@NonNull final Tracks currentTracks) {
- super.onTextTracksChanged(currentTracks);
-
- final boolean trackTypeTextSupported = !currentTracks.containsType(C.TRACK_TYPE_TEXT)
- || currentTracks.isTypeSupported(C.TRACK_TYPE_TEXT, false);
- if (getPlayer().getTrackSelector().getCurrentMappedTrackInfo() == null
- || !trackTypeTextSupported) {
- binding.captionTextView.setVisibility(View.GONE);
- return;
- }
-
- // Extract all loaded languages
- final List textTracks = currentTracks
- .getGroups()
- .stream()
- .filter(trackGroupInfo -> C.TRACK_TYPE_TEXT == trackGroupInfo.getType())
- .collect(Collectors.toList());
- final List availableLanguages = textTracks.stream()
- .map(Tracks.Group::getMediaTrackGroup)
- .filter(textTrack -> textTrack.length > 0)
- .map(textTrack -> textTrack.getFormat(0).language)
- .collect(Collectors.toList());
-
- // Find selected text track
- final Optional selectedTracks = textTracks.stream()
- .filter(Tracks.Group::isSelected)
- .filter(info -> info.getMediaTrackGroup().length >= 1)
- .map(info -> info.getMediaTrackGroup().getFormat(0))
- .findFirst();
-
- // Build UI
- buildCaptionMenu(availableLanguages);
- //noinspection SimplifyOptionalCallChains
- if (player.getTrackSelector().getParameters().getRendererDisabled(
- player.getCaptionRendererIndex()) || !selectedTracks.isPresent()) {
- binding.captionTextView.setText(R.string.caption_none);
- } else {
- binding.captionTextView.setText(selectedTracks.get().language);
- }
- binding.captionTextView.setVisibility(
- availableLanguages.isEmpty() ? View.GONE : View.VISIBLE);
- }
+ //region Other player listeners
@Override
public void onPlaybackParametersChanged(@NonNull final PlaybackParameters playbackParameters) {
@@ -1004,12 +967,6 @@ public abstract class VideoPlayerUi extends PlayerUi
//TODO check if this causes black screen when switching to fullscreen
animate(binding.surfaceForeground, false, DEFAULT_CONTROLS_DURATION);
}
-
- @Override
- public void onCues(@NonNull List cues) {
- super.onCues(cues);
- binding.subtitleView.setCues(cues);
- }
//endregion
@@ -1017,6 +974,7 @@ public abstract class VideoPlayerUi extends PlayerUi
// Metadata & stream related views
//////////////////////////////////////////////////////////////////////////*/
//region Metadata & stream related views
+
@Override
public void onMetadataChanged(@NonNull final StreamInfo info) {
super.onMetadataChanged(info);
@@ -1092,6 +1050,7 @@ public abstract class VideoPlayerUi extends PlayerUi
// Popup menus ("popup" means that they pop up, not that they belong to the popup player)
//////////////////////////////////////////////////////////////////////////*/
//region Popup menus ("popup" means that they pop up, not that they belong to the popup player)
+
private void buildQualityMenu() {
if (qualityPopupMenu == null) {
return;
@@ -1315,6 +1274,57 @@ public abstract class VideoPlayerUi extends PlayerUi
// Captions (text tracks)
//////////////////////////////////////////////////////////////////////////*/
//region Captions (text tracks)
+
+ @Override
+ public void onTextTracksChanged(@NonNull final Tracks currentTracks) {
+ super.onTextTracksChanged(currentTracks);
+
+ final boolean trackTypeTextSupported = !currentTracks.containsType(C.TRACK_TYPE_TEXT)
+ || currentTracks.isTypeSupported(C.TRACK_TYPE_TEXT, false);
+ if (getPlayer().getTrackSelector().getCurrentMappedTrackInfo() == null
+ || !trackTypeTextSupported) {
+ binding.captionTextView.setVisibility(View.GONE);
+ return;
+ }
+
+ // Extract all loaded languages
+ final List textTracks = currentTracks
+ .getGroups()
+ .stream()
+ .filter(trackGroupInfo -> C.TRACK_TYPE_TEXT == trackGroupInfo.getType())
+ .collect(Collectors.toList());
+ final List availableLanguages = textTracks.stream()
+ .map(Tracks.Group::getMediaTrackGroup)
+ .filter(textTrack -> textTrack.length > 0)
+ .map(textTrack -> textTrack.getFormat(0).language)
+ .collect(Collectors.toList());
+
+ // Find selected text track
+ final Optional selectedTracks = textTracks.stream()
+ .filter(Tracks.Group::isSelected)
+ .filter(info -> info.getMediaTrackGroup().length >= 1)
+ .map(info -> info.getMediaTrackGroup().getFormat(0))
+ .findFirst();
+
+ // Build UI
+ buildCaptionMenu(availableLanguages);
+ //noinspection SimplifyOptionalCallChains
+ if (player.getTrackSelector().getParameters().getRendererDisabled(
+ player.getCaptionRendererIndex()) || !selectedTracks.isPresent()) {
+ binding.captionTextView.setText(R.string.caption_none);
+ } else {
+ binding.captionTextView.setText(selectedTracks.get().language);
+ }
+ binding.captionTextView.setVisibility(
+ availableLanguages.isEmpty() ? View.GONE : View.VISIBLE);
+ }
+
+ @Override
+ public void onCues(@NonNull List cues) {
+ super.onCues(cues);
+ binding.subtitleView.setCues(cues);
+ }
+
private void setupSubtitleView() {
setupSubtitleView(PlayerHelper.getCaptionScale(context));
final CaptionStyleCompat captionStyle = PlayerHelper.getCaptionStyle(context);
@@ -1330,6 +1340,7 @@ public abstract class VideoPlayerUi extends PlayerUi
// Click listeners
//////////////////////////////////////////////////////////////////////////*/
//region Click listeners
+
@Override
public void onClick(final View v) {
if (DEBUG) {
@@ -1493,9 +1504,10 @@ public abstract class VideoPlayerUi extends PlayerUi
/*//////////////////////////////////////////////////////////////////////////
- // Video size, resize, orientation, fullscreen
+ // Video size
//////////////////////////////////////////////////////////////////////////*/
- //region Video size, resize, orientation, fullscreen
+ //region Video size
+
protected void setResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode) {
binding.surfaceView.setResizeMode(resizeMode);
binding.resizeTextView.setText(PlayerHelper.resizeTypeOf(context, resizeMode));
@@ -1569,6 +1581,7 @@ public abstract class VideoPlayerUi extends PlayerUi
// Getters
//////////////////////////////////////////////////////////////////////////*/
//region Getters
+
public PlayerBinding getBinding() {
return binding;
}
From 1b39b5376f518ee570258da82fbe4fb09d11c231 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Fri, 15 Apr 2022 00:01:59 +0200
Subject: [PATCH 036/152] Add some javadocs; move preparing player uis to
PlayerUiList
---
.../org/schabi/newpipe/player/Player.java | 25 ++---
.../schabi/newpipe/player/ui/PlayerUi.java | 92 ++++++++++++++++++-
.../newpipe/player/ui/PlayerUiList.java | 43 ++++++++-
3 files changed, 138 insertions(+), 22 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java
index b0fed3d7d..f8ea7bc90 100644
--- a/app/src/main/java/org/schabi/newpipe/player/Player.java
+++ b/app/src/main/java/org/schabi/newpipe/player/Player.java
@@ -447,7 +447,7 @@ public final class Player implements PlaybackListener, Listener {
private void initUIsForCurrentPlayerType() {
//noinspection SimplifyOptionalCallChains
if (!UIs.get(NotificationPlayerUi.class).isPresent()) {
- UIs.add(new NotificationPlayerUi(this));
+ UIs.addAndPrepare(new NotificationPlayerUi(this));
}
if ((UIs.get(MainPlayerUi.class).isPresent() && playerType == PlayerType.MAIN)
@@ -469,24 +469,15 @@ public final class Player implements PlaybackListener, Listener {
switch (playerType) {
case MAIN:
UIs.destroyAll(PopupPlayerUi.class);
- UIs.add(new MainPlayerUi(this, binding));
+ UIs.addAndPrepare(new MainPlayerUi(this, binding));
+ break;
+ case POPUP:
+ UIs.destroyAll(MainPlayerUi.class);
+ UIs.addAndPrepare(new PopupPlayerUi(this, binding));
break;
case AUDIO:
UIs.destroyAll(VideoPlayerUi.class);
break;
- case POPUP:
- UIs.destroyAll(MainPlayerUi.class);
- UIs.add(new PopupPlayerUi(this, binding));
- break;
- }
-
- if (fragmentListener != null) {
- // make sure UIs know whether a service is connected or not
- UIs.call(PlayerUi::onFragmentListenerSet);
- }
- if (!exoPlayerIsNull()) {
- UIs.call(PlayerUi::initPlayer);
- UIs.call(PlayerUi::initPlayback);
}
}
@@ -1968,9 +1959,9 @@ public final class Player implements PlaybackListener, Listener {
/*//////////////////////////////////////////////////////////////////////////
- // Video size, resize, orientation, fullscreen
+ // Video size
//////////////////////////////////////////////////////////////////////////*/
- //region Video size, resize, orientation, fullscreen
+ //region Video size
@Override // exoplayer listener
public void onVideoSizeChanged(@NonNull final VideoSize videoSize) {
if (DEBUG) {
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
index 81e93ca23..c4db1f334 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
@@ -18,50 +18,105 @@ import org.schabi.newpipe.player.Player;
import java.util.List;
+/**
+ * A player UI is a component that can seamlessly connect and disconnect from the {@link Player} and
+ * provide a user interface of some sort. Try to extend this class instead of adding more code to
+ * {@link Player}!
+ */
public abstract class PlayerUi {
- @NonNull protected Context context;
- @NonNull protected Player player;
+ @NonNull protected final Context context;
+ @NonNull protected final Player player;
+ /**
+ * @param player the player instance that will be usable throughout the lifetime of this UI
+ */
public PlayerUi(@NonNull final Player player) {
this.context = player.getContext();
this.player = player;
}
+ /**
+ * @return the player instance this UI was constructed with
+ */
@NonNull
public Player getPlayer() {
return player;
}
+ /**
+ * Called after the player received an intent and processed it
+ */
public void setupAfterIntent() {
}
+ /**
+ * Called right after the exoplayer instance is constructed, or right after this UI is
+ * constructed if the exoplayer is already available then. Note that the exoplayer instance
+ * could be built and destroyed multiple times during the lifetime of the player, so this method
+ * might be called multiple times.
+ */
public void initPlayer() {
}
+ /**
+ * Called when playback in the exoplayer is about to start, or right after this UI is
+ * constructed if the exoplayer and the play queue are already available then. The play queue
+ * will therefore always be not null.
+ */
public void initPlayback() {
}
+ /**
+ * Called when the exoplayer instance is about to be destroyed. Note that the exoplayer instance
+ * could be built and destroyed multiple times during the lifetime of the player, so this method
+ * might be called multiple times. Be sure to unset any video surface view or play queue
+ * listeners! This will also be called when this UI is being discarded, just before {@link
+ * #destroy()}.
+ */
public void destroyPlayer() {
}
+ /**
+ * Called when this UI is being discarded, either because the player is switching to a different
+ * UI or because the player is shutting down completely
+ */
public void destroy() {
}
+ /**
+ * Called when the player is smooth-stopping, that is, transitioning smoothly to a new play
+ * queue after the user tapped on a new video stream while a stream was playing in the video
+ * detail fragment
+ */
public void smoothStopForImmediateReusing() {
}
+ /**
+ * Called when the video detail fragment listener is connected with the player, or right after
+ * this UI is constructed if the listener is already connected then
+ */
public void onFragmentListenerSet() {
}
/**
- * If you want to register new broadcast actions to receive here, add them to
- * {@link Player#setupBroadcastReceiver()}.
+ * Broadcasts that the player receives will also be notified to UIs here. If you want to
+ * register new broadcast actions to receive here, add them to {@link
+ * Player#setupBroadcastReceiver()}.
*/
public void onBroadcastReceived(final Intent intent) {
}
+ /**
+ * Called when stream progress (i.e. the current time in the seekbar) or stream duration change.
+ * Will surely be called every {@link Player#PROGRESS_LOOP_INTERVAL_MILLIS} while a stream is
+ * playing.
+ * @param currentProgress the current progress in milliseconds
+ * @param duration the duration of the stream being played
+ * @param bufferPercent the percentage of stream already buffered, see {@link
+ * com.google.android.exoplayer2.BasePlayer#getBufferedPercentage()}
+ */
public void onUpdateProgress(final int currentProgress,
final int duration,
final int bufferPercent) {
@@ -97,27 +152,56 @@ public abstract class PlayerUi {
public void onMuteUnmuteChanged(final boolean isMuted) {
}
+ /**
+ * @see com.google.android.exoplayer2.Player.Listener#onTracksChanged(Tracks)
+ */
public void onTextTracksChanged(@NonNull final Tracks currentTracks) {
}
+ /**
+ * @see com.google.android.exoplayer2.Player.Listener#onPlaybackParametersChanged
+ */
public void onPlaybackParametersChanged(@NonNull final PlaybackParameters playbackParameters) {
}
+ /**
+ * @see com.google.android.exoplayer2.Player.Listener#onRenderedFirstFrame
+ */
public void onRenderedFirstFrame() {
}
+ /**
+ * @see com.google.android.exoplayer2.text.TextOutput#onCues
+ */
public void onCues(@NonNull final List cues) {
}
+ /**
+ * Called when the stream being played changes
+ * @param info the {@link StreamInfo} metadata object, along with data about the selected and
+ * available video streams (to be used to build the resolution menus, for example)
+ */
public void onMetadataChanged(@NonNull final StreamInfo info) {
}
+ /**
+ * Called when the thumbnail for the current metadata was loaded
+ * @param bitmap the thumbnail to process, or null if there is no thumbnail or there was an
+ * error when loading the thumbnail
+ */
public void onThumbnailLoaded(@Nullable final Bitmap bitmap) {
}
+ /**
+ * Called when the play queue was edited: a stream was appended, moved or removed.
+ */
public void onPlayQueueEdited() {
}
+ /**
+ * @param videoSize the new video size, useful to set the surface aspect ratio
+ * @see com.google.android.exoplayer2.Player.Listener#onVideoSizeChanged
+ */
public void onVideoSizeChanged(@NonNull final VideoSize videoSize) {
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java
index 8c5c0dbfa..749cda02c 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java
@@ -8,10 +8,39 @@ import java.util.function.Consumer;
public final class PlayerUiList {
final List playerUis = new ArrayList<>();
- public void add(final PlayerUi playerUi) {
+ /**
+ * Adds the provided player ui to the list and calls on it the initialization functions that
+ * apply based on the current player state. The preparation step needs to be done since when UIs
+ * are removed and re-added, the player will not call e.g. initPlayer again since the exoplayer
+ * is already initialized, but we need to notify the newly built UI that the player is ready
+ * nonetheless.
+ * @param playerUi the player ui to prepare and add to the list; its {@link
+ * PlayerUi#getPlayer()} will be used to query information about the player
+ * state
+ */
+ public void addAndPrepare(final PlayerUi playerUi) {
+ if (playerUi.getPlayer().getFragmentListener().isPresent()) {
+ // make sure UIs know whether a service is connected or not
+ playerUi.onFragmentListenerSet();
+ }
+
+ if (!playerUi.getPlayer().exoPlayerIsNull()) {
+ playerUi.initPlayer();
+ if (playerUi.getPlayer().getPlayQueue() != null) {
+ playerUi.initPlayback();
+ }
+ }
+
playerUis.add(playerUi);
}
+ /**
+ * Destroys all matching player UIs and removes them from the list
+ * @param playerUiType the class of the player UI to destroy; the {@link
+ * Class#isInstance(Object)} method will be used, so even subclasses will be
+ * destroyed and removed
+ * @param the class type parameter
+ */
public void destroyAll(final Class playerUiType) {
playerUis.stream()
.filter(playerUiType::isInstance)
@@ -22,6 +51,14 @@ public final class PlayerUiList {
playerUis.removeIf(playerUiType::isInstance);
}
+ /**
+ * @param playerUiType the class of the player UI to return; the {@link
+ * Class#isInstance(Object)} method will be used, so even subclasses could
+ * be returned
+ * @param the class type parameter
+ * @return the first player UI of the required type found in the list, or an empty {@link
+ * Optional} otherwise
+ */
public Optional get(final Class playerUiType) {
return playerUis.stream()
.filter(playerUiType::isInstance)
@@ -29,6 +66,10 @@ public final class PlayerUiList {
.findFirst();
}
+ /**
+ * Calls the provided consumer on all player UIs in the list
+ * @param consumer the consumer to call with player UIs
+ */
public void call(final Consumer consumer) {
//noinspection SimplifyStreamApiCallChains
playerUis.stream().forEach(consumer);
From a19073ec011e7c314ccab2e9d84d466d235fd24a Mon Sep 17 00:00:00 2001
From: Stypox
Date: Sat, 16 Apr 2022 12:03:59 +0200
Subject: [PATCH 037/152] Restore checkstyle and solve its errors
---
app/build.gradle | 2 +-
.../fragments/detail/VideoDetailFragment.java | 25 +++++++++----------
.../org/schabi/newpipe/player/Player.java | 6 +++--
.../player/notification/NotificationUtil.java | 4 +--
.../player/playback/PlayerMediaSession.java | 2 --
.../newpipe/player/ui/MainPlayerUi.java | 2 +-
.../schabi/newpipe/player/ui/PlayerUi.java | 16 +++++++-----
.../newpipe/player/ui/PlayerUiList.java | 4 +--
.../newpipe/player/ui/VideoPlayerUi.java | 15 ++++++-----
.../custom/NotificationActionsPreference.java | 1 -
10 files changed, 41 insertions(+), 36 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 46eee8d00..9867037e6 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -166,7 +166,7 @@ afterEvaluate {
if (!System.properties.containsKey('skipFormatKtlint')) {
preDebugBuild.dependsOn formatKtlint
}
- //preDebugBuild.dependsOn runCheckstyle, runKtlint
+ preDebugBuild.dependsOn runCheckstyle, runKtlint
}
sonarqube {
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 cb8f0961f..8ffff2f9e 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
@@ -1,5 +1,16 @@
package org.schabi.newpipe.fragments.detail;
+import static android.text.TextUtils.isEmpty;
+import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
+import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
+import static org.schabi.newpipe.ktx.ViewUtils.animate;
+import static org.schabi.newpipe.ktx.ViewUtils.animateRotation;
+import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
+import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
+import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
+import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
+import static org.schabi.newpipe.util.ListHelper.getUrlAndNonTorrentStreams;
+
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.BroadcastReceiver;
@@ -43,7 +54,6 @@ import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
-import androidx.viewbinding.ViewBinding;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters;
@@ -78,9 +88,9 @@ import org.schabi.newpipe.fragments.list.videos.RelatedItemsFragment;
import org.schabi.newpipe.ktx.AnimationType;
import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.local.history.HistoryRecordManager;
+import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.PlayerService.PlayerType;
-import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.event.OnKeyDownListener;
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener;
import org.schabi.newpipe.player.helper.PlayerHelper;
@@ -118,17 +128,6 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
-import static android.text.TextUtils.isEmpty;
-import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
-import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
-import static org.schabi.newpipe.ktx.ViewUtils.animate;
-import static org.schabi.newpipe.ktx.ViewUtils.animateRotation;
-import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
-import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
-import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
-import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
-import static org.schabi.newpipe.util.ListHelper.getUrlAndNonTorrentStreams;
-
public final class VideoDetailFragment
extends BaseStateFragment
implements BackPressable,
diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java
index f8ea7bc90..0755f9b4d 100644
--- a/app/src/main/java/org/schabi/newpipe/player/Player.java
+++ b/app/src/main/java/org/schabi/newpipe/player/Player.java
@@ -239,6 +239,7 @@ public final class Player implements PlaybackListener, Listener {
// UIs, listeners and disposables
//////////////////////////////////////////////////////////////////////////*/
+ @SuppressWarnings("MemberName") // keep the unusual member name
private final PlayerUiList UIs = new PlayerUiList();
private BroadcastReceiver broadcastReceiver;
@@ -1148,7 +1149,7 @@ public final class Player implements PlaybackListener, Listener {
simpleExoPlayer.setRepeatMode(repeatMode);
}
}
-
+
public void cycleNextRepeatMode() {
setRepeatMode(nextRepeatMode(getRepeatMode()));
}
@@ -1181,7 +1182,7 @@ public final class Player implements PlaybackListener, Listener {
UIs.call(playerUi -> playerUi.onShuffleModeEnabledChanged(shuffleModeEnabled));
notifyPlaybackUpdateToListeners();
}
-
+
public void toggleShuffleModeEnabled() {
if (!exoPlayerIsNull()) {
simpleExoPlayer.setShuffleModeEnabled(!simpleExoPlayer.getShuffleModeEnabled());
@@ -2301,6 +2302,7 @@ public final class Player implements PlaybackListener, Listener {
/**
* @return the user interfaces connected with the player
*/
+ @SuppressWarnings("MethodName") // keep the unusual method name
public PlayerUiList UIs() {
return UIs;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java
index 5f0052453..28c3b3655 100644
--- a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java
+++ b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java
@@ -132,7 +132,7 @@ public final class NotificationUtil {
// also update content intent, in case the user switched players
notificationBuilder.setContentIntent(PendingIntent.getActivity(player.getContext(),
- NOTIFICATION_ID, getIntentForNotification(player), FLAG_UPDATE_CURRENT));
+ NOTIFICATION_ID, getIntentForNotification(), FLAG_UPDATE_CURRENT));
notificationBuilder.setContentTitle(player.getVideoTitle());
notificationBuilder.setContentText(player.getUploaderName());
notificationBuilder.setTicker(player.getVideoTitle());
@@ -321,7 +321,7 @@ public final class NotificationUtil {
new Intent(intentAction), FLAG_UPDATE_CURRENT));
}
- private Intent getIntentForNotification(final Player player) {
+ private Intent getIntentForNotification() {
if (player.audioPlayerSelected() || player.popupPlayerSelected()) {
// Means we play in popup or audio only. Let's show the play queue
return NavigationHelper.getPlayQueueActivityIntent(player.getContext());
diff --git a/app/src/main/java/org/schabi/newpipe/player/playback/PlayerMediaSession.java b/app/src/main/java/org/schabi/newpipe/player/playback/PlayerMediaSession.java
index 2f261a0fa..3be9b6173 100644
--- a/app/src/main/java/org/schabi/newpipe/player/playback/PlayerMediaSession.java
+++ b/app/src/main/java/org/schabi/newpipe/player/playback/PlayerMediaSession.java
@@ -10,8 +10,6 @@ import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.ui.VideoPlayerUi;
-import java.util.Optional;
-
public class PlayerMediaSession implements MediaSessionCallback {
private final Player player;
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
index c62382782..3bdda0029 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
@@ -497,7 +497,7 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
//region Captions (text tracks)
@Override
- protected void setupSubtitleView(float captionScale) {
+ protected void setupSubtitleView(final float captionScale) {
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels);
final float captionRatioInverse = 20f + 4f * (1.0f - captionScale);
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
index c4db1f334..499800690 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
@@ -46,7 +46,7 @@ public abstract class PlayerUi {
/**
- * Called after the player received an intent and processed it
+ * Called after the player received an intent and processed it.
*/
public void setupAfterIntent() {
}
@@ -80,7 +80,7 @@ public abstract class PlayerUi {
/**
* Called when this UI is being discarded, either because the player is switching to a different
- * UI or because the player is shutting down completely
+ * UI or because the player is shutting down completely.
*/
public void destroy() {
}
@@ -88,14 +88,14 @@ public abstract class PlayerUi {
/**
* Called when the player is smooth-stopping, that is, transitioning smoothly to a new play
* queue after the user tapped on a new video stream while a stream was playing in the video
- * detail fragment
+ * detail fragment.
*/
public void smoothStopForImmediateReusing() {
}
/**
* Called when the video detail fragment listener is connected with the player, or right after
- * this UI is constructed if the listener is already connected then
+ * this UI is constructed if the listener is already connected then.
*/
public void onFragmentListenerSet() {
}
@@ -104,6 +104,7 @@ public abstract class PlayerUi {
* Broadcasts that the player receives will also be notified to UIs here. If you want to
* register new broadcast actions to receive here, add them to {@link
* Player#setupBroadcastReceiver()}.
+ * @param intent the broadcast intent received by the player
*/
public void onBroadcastReceived(final Intent intent) {
}
@@ -154,12 +155,14 @@ public abstract class PlayerUi {
/**
* @see com.google.android.exoplayer2.Player.Listener#onTracksChanged(Tracks)
+ * @param currentTracks the available tracks information
*/
public void onTextTracksChanged(@NonNull final Tracks currentTracks) {
}
/**
* @see com.google.android.exoplayer2.Player.Listener#onPlaybackParametersChanged
+ * @param playbackParameters the new playback parameters
*/
public void onPlaybackParametersChanged(@NonNull final PlaybackParameters playbackParameters) {
}
@@ -172,12 +175,13 @@ public abstract class PlayerUi {
/**
* @see com.google.android.exoplayer2.text.TextOutput#onCues
+ * @param cues the cues to pass to the subtitle view
*/
public void onCues(@NonNull final List cues) {
}
/**
- * Called when the stream being played changes
+ * Called when the stream being played changes.
* @param info the {@link StreamInfo} metadata object, along with data about the selected and
* available video streams (to be used to build the resolution menus, for example)
*/
@@ -185,7 +189,7 @@ public abstract class PlayerUi {
}
/**
- * Called when the thumbnail for the current metadata was loaded
+ * Called when the thumbnail for the current metadata was loaded.
* @param bitmap the thumbnail to process, or null if there is no thumbnail or there was an
* error when loading the thumbnail
*/
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java
index 749cda02c..05c0ed5b3 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUiList.java
@@ -35,7 +35,7 @@ public final class PlayerUiList {
}
/**
- * Destroys all matching player UIs and removes them from the list
+ * Destroys all matching player UIs and removes them from the list.
* @param playerUiType the class of the player UI to destroy; the {@link
* Class#isInstance(Object)} method will be used, so even subclasses will be
* destroyed and removed
@@ -67,7 +67,7 @@ public final class PlayerUiList {
}
/**
- * Calls the provided consumer on all player UIs in the list
+ * Calls the provided consumer on all player UIs in the list.
* @param consumer the consumer to call with player UIs
*/
public void call(final Consumer consumer) {
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
index f4ebc3304..393bf141b 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
@@ -86,7 +86,8 @@ import java.util.Optional;
import java.util.stream.Collectors;
public abstract class VideoPlayerUi extends PlayerUi
- implements SeekBar.OnSeekBarChangeListener, View.OnClickListener, View.OnLongClickListener, PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener {
+ implements SeekBar.OnSeekBarChangeListener, View.OnClickListener, View.OnLongClickListener,
+ PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener {
private static final String TAG = VideoPlayerUi.class.getSimpleName();
// time constants
@@ -476,7 +477,7 @@ public abstract class VideoPlayerUi extends PlayerUi
binding.endScreen.setImageBitmap(endScreenBitmap);
}
- protected abstract float calculateMaxEndScreenThumbnailHeight(@NonNull final Bitmap bitmap);
+ protected abstract float calculateMaxEndScreenThumbnailHeight(@NonNull Bitmap bitmap);
//endregion
@@ -511,6 +512,7 @@ public abstract class VideoPlayerUi extends PlayerUi
/**
* Sets the current duration into the corresponding elements.
+ * @param currentProgress the current progress, in milliseconds
*/
private void updatePlayBackElementsCurrentDuration(final int currentProgress) {
// Don't set seekbar progress while user is seeking
@@ -522,6 +524,7 @@ public abstract class VideoPlayerUi extends PlayerUi
/**
* Sets the video duration time into all control components (e.g. seekbar).
+ * @param duration the video duration, in milliseconds
*/
private void setVideoDurationToControls(final int duration) {
binding.playbackEndTime.setText(getTimeString(duration));
@@ -1214,7 +1217,7 @@ public abstract class VideoPlayerUi extends PlayerUi
final MediaItemTag.Quality quality = currentMetadata.getMaybeQuality().get();
final List availableStreams = quality.getSortedVideoStreams();
final int selectedStreamIndex = quality.getSelectedVideoStreamIndex();
- if (selectedStreamIndex == menuItemIndex|| availableStreams.size() <= menuItemIndex) {
+ if (selectedStreamIndex == menuItemIndex || availableStreams.size() <= menuItemIndex) {
return true;
}
@@ -1320,7 +1323,7 @@ public abstract class VideoPlayerUi extends PlayerUi
}
@Override
- public void onCues(@NonNull List cues) {
+ public void onCues(@NonNull final List cues) {
super.onCues(cues);
binding.subtitleView.setCues(cues);
}
@@ -1332,7 +1335,7 @@ public abstract class VideoPlayerUi extends PlayerUi
binding.subtitleView.setStyle(captionStyle);
}
- protected abstract void setupSubtitleView(final float captionScale);
+ protected abstract void setupSubtitleView(float captionScale);
//endregion
@@ -1518,7 +1521,7 @@ public abstract class VideoPlayerUi extends PlayerUi
}
@Override
- public void onVideoSizeChanged(@NonNull VideoSize videoSize) {
+ public void onVideoSizeChanged(@NonNull final VideoSize videoSize) {
super.onVideoSizeChanged(videoSize);
binding.surfaceView.setAspectRatio(((float) videoSize.width) / videoSize.height);
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/custom/NotificationActionsPreference.java b/app/src/main/java/org/schabi/newpipe/settings/custom/NotificationActionsPreference.java
index dfcf2e597..b4f6d598a 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/custom/NotificationActionsPreference.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/custom/NotificationActionsPreference.java
@@ -28,7 +28,6 @@ import androidx.preference.PreferenceViewHolder;
import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
-import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.notification.NotificationConstants;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ThemeHelper;
From 4979f84e4116d114dca851a31d706bec90a93450 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Sat, 16 Apr 2022 16:01:23 +0200
Subject: [PATCH 038/152] Solve some Sonarlint warnings
---
.../newpipe/local/dialog/PlaylistDialog.java | 37 ++++++++++++++--
.../newpipe/player/PlayQueueActivity.java | 8 ++--
.../org/schabi/newpipe/player/Player.java | 42 +------------------
.../schabi/newpipe/player/PlayerService.java | 17 ++++----
.../gesture/BasePlayerGestureListener.kt | 5 ++-
.../player/notification/NotificationUtil.java | 1 +
.../newpipe/player/ui/MainPlayerUi.java | 13 +++---
.../schabi/newpipe/player/ui/PlayerUi.java | 2 +-
.../newpipe/player/ui/PopupPlayerUi.java | 16 ++++---
.../newpipe/player/ui/VideoPlayerUi.java | 40 +++++++++---------
10 files changed, 86 insertions(+), 95 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java
index f568ef81a..dec8b05b2 100644
--- a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java
+++ b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java
@@ -9,15 +9,20 @@ import android.view.Window;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.FragmentManager;
import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
+import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.util.StateSaver;
import java.util.List;
+import java.util.Objects;
import java.util.Queue;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.Disposable;
@@ -131,13 +136,13 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
* @param context context used for accessing the database
* @param streamEntities used for crating the dialog
* @param onExec execution that should occur after a dialog got created, e.g. showing it
- * @return Disposable
+ * @return the disposable that was created
*/
public static Disposable createCorrespondingDialog(
final Context context,
final List streamEntities,
- final Consumer onExec
- ) {
+ final Consumer onExec) {
+
return new LocalPlaylistManager(NewPipeDatabase.getInstance(context))
.hasPlaylists()
.observeOn(AndroidSchedulers.mainThread())
@@ -147,4 +152,30 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
: PlaylistCreationDialog.newInstance(streamEntities))
);
}
+
+ /**
+ * Creates a {@link PlaylistAppendDialog} when playlists exists,
+ * otherwise a {@link PlaylistCreationDialog}. If the player's play queue is null or empty, no
+ * dialog will be created.
+ *
+ * @param player the player from which to extract the context and the play queue
+ * @param fragmentManager the fragment manager to use to show the dialog
+ * @return the disposable that was created
+ */
+ public static Disposable showForPlayQueue(
+ final Player player,
+ @NonNull final FragmentManager fragmentManager) {
+
+ final List streamEntities = Stream.of(player.getPlayQueue())
+ .filter(Objects::nonNull)
+ .flatMap(playQueue -> Objects.requireNonNull(playQueue).getStreams().stream())
+ .map(StreamEntity::new)
+ .collect(Collectors.toList());
+ if (streamEntities.isEmpty()) {
+ return Disposable.empty();
+ }
+
+ return PlaylistDialog.createCorrespondingDialog(player.getContext(), streamEntities,
+ dialog -> dialog.show(fragmentManager, "PlaylistDialog"));
+ }
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java
index cdba900f9..c18a7f487 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java
@@ -29,6 +29,7 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.ActivityPlayerQueueControlBinding;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
+import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.player.event.PlayerEventListener;
import org.schabi.newpipe.player.helper.PlaybackParameterDialog;
import org.schabi.newpipe.player.playqueue.PlayQueue;
@@ -53,8 +54,6 @@ public final class PlayQueueActivity extends AppCompatActivity
private Player player;
- private PlayQueueAdapter adapter = null;
-
private boolean serviceBound;
private ServiceConnection serviceConnection;
@@ -128,7 +127,7 @@ public final class PlayQueueActivity extends AppCompatActivity
NavigationHelper.openSettings(this);
return true;
case R.id.action_append_playlist:
- player.onAddToPlaylistClicked(getSupportFragmentManager());
+ PlaylistDialog.showForPlayQueue(player, getSupportFragmentManager());
return true;
case R.id.action_playback_speed:
openPlaybackParameterDialog();
@@ -441,10 +440,9 @@ public final class PlayQueueActivity extends AppCompatActivity
@Override
public void onQueueUpdate(@Nullable final PlayQueue queue) {
if (queue == null) {
- adapter = null;
queueControlBinding.playQueue.setAdapter(null);
} else {
- adapter = new PlayQueueAdapter(this, queue);
+ final PlayQueueAdapter adapter = new PlayQueueAdapter(this, queue);
adapter.setSelectedListener(getOnSelectedListener());
queueControlBinding.playQueue.setAdapter(adapter);
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java
index 0755f9b4d..2d44c6449 100644
--- a/app/src/main/java/org/schabi/newpipe/player/Player.java
+++ b/app/src/main/java/org/schabi/newpipe/player/Player.java
@@ -63,16 +63,6 @@ import android.view.LayoutInflater;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.content.res.AppCompatResources;
-import androidx.appcompat.view.ContextThemeWrapper;
-import androidx.appcompat.widget.AppCompatImageButton;
-import androidx.appcompat.widget.PopupMenu;
-import androidx.core.content.ContextCompat;
-import androidx.core.graphics.Insets;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
-import androidx.fragment.app.FragmentManager;
import androidx.preference.PreferenceManager;
import com.google.android.exoplayer2.C;
@@ -96,7 +86,6 @@ import com.squareup.picasso.Target;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
-import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.databinding.PlayerBinding;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.ErrorUtil;
@@ -105,7 +94,6 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
-import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.player.PlayerService.PlayerType;
import org.schabi.newpipe.player.event.PlayerEventListener;
@@ -116,6 +104,7 @@ import org.schabi.newpipe.player.helper.MediaSessionManager;
import org.schabi.newpipe.player.helper.PlayerDataSource;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.mediaitem.MediaItemTag;
+import org.schabi.newpipe.player.notification.NotificationPlayerUi;
import org.schabi.newpipe.player.playback.MediaSourceManager;
import org.schabi.newpipe.player.playback.PlaybackListener;
import org.schabi.newpipe.player.playback.PlayerMediaSession;
@@ -125,7 +114,6 @@ import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver.SourceType;
import org.schabi.newpipe.player.ui.MainPlayerUi;
-import org.schabi.newpipe.player.notification.NotificationPlayerUi;
import org.schabi.newpipe.player.ui.PlayerUi;
import org.schabi.newpipe.player.ui.PlayerUiList;
import org.schabi.newpipe.player.ui.PopupPlayerUi;
@@ -137,10 +125,8 @@ import org.schabi.newpipe.util.PicassoHelper;
import org.schabi.newpipe.util.SerializedCache;
import org.schabi.newpipe.util.StreamTypeUtil;
-import java.util.Collections;
import java.util.List;
import java.util.Optional;
-import java.util.stream.Collectors;
import java.util.stream.IntStream;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
@@ -1192,32 +1178,6 @@ public final class Player implements PlaybackListener, Listener {
- /*//////////////////////////////////////////////////////////////////////////
- // Playlist append TODO this does not make sense here
- //////////////////////////////////////////////////////////////////////////*/
- //region Playlist append
-
- public void onAddToPlaylistClicked(@NonNull final FragmentManager fragmentManager) {
- if (DEBUG) {
- Log.d(TAG, "onAddToPlaylistClicked() called");
- }
-
- if (getPlayQueue() != null) {
- PlaylistDialog.createCorrespondingDialog(
- getContext(),
- getPlayQueue()
- .getStreams()
- .stream()
- .map(StreamEntity::new)
- .collect(Collectors.toList()),
- dialog -> dialog.show(fragmentManager, TAG)
- );
- }
- }
- //endregion
-
-
-
/*//////////////////////////////////////////////////////////////////////////
// Mute / Unmute
//////////////////////////////////////////////////////////////////////////*/
diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
index b5014eeed..326b01590 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
@@ -71,16 +71,17 @@ public final class PlayerService extends Service {
Log.d(TAG, "onStartCommand() called with: intent = [" + intent
+ "], flags = [" + flags + "], startId = [" + startId + "]");
}
- if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
- && player.getPlayQueue() == null) {
- // Player is not working, no need to process media button's action
- return START_NOT_STICKY;
+
+ if (!Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
+ || player.getPlayQueue() != null) {
+ // ^ no need to process media button's action if player is not working
+
+ player.handleIntent(intent);
+ if (player.getMediaSessionManager() != null) {
+ player.getMediaSessionManager().handleMediaButtonIntent(intent);
+ }
}
- player.handleIntent(intent);
- if (player.getMediaSessionManager() != null) {
- player.getMediaSessionManager().handleMediaButtonIntent(intent);
- }
return START_NOT_STICKY;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt
index bd5d6f1c5..b006e73aa 100644
--- a/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt
@@ -92,7 +92,10 @@ abstract class BasePlayerGestureListener(
return true
}
- return if (onDownNotDoubleTapping(e)) super.onDown(e) else true
+ if (onDownNotDoubleTapping(e)) {
+ return super.onDown(e)
+ }
+ return true
}
/**
diff --git a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java
index 28c3b3655..2ba754500 100644
--- a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java
+++ b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java
@@ -266,6 +266,7 @@ public final class NotificationUtil {
null);
}
+ // fallthrough
case NotificationConstants.PLAY_PAUSE:
if (player.getCurrentState() == Player.STATE_COMPLETED) {
return getAction(R.drawable.ic_replay,
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
index 3bdda0029..eebcc81c4 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
@@ -51,6 +51,7 @@ import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.info_list.StreamSegmentAdapter;
import org.schabi.newpipe.ktx.AnimationType;
+import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.event.PlayerServiceEventListener;
import org.schabi.newpipe.player.gesture.BasePlayerGestureListener;
@@ -147,7 +148,8 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
binding.addToPlaylistButton.setOnClickListener(v ->
getParentActivity().map(FragmentActivity::getSupportFragmentManager)
- .ifPresent(player::onAddToPlaylistClicked));
+ .ifPresent(fragmentManager ->
+ PlaylistDialog.showForPlayQueue(player, fragmentManager)));
settingsContentObserver = new ContentObserver(new Handler()) {
@Override
@@ -401,6 +403,7 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
//////////////////////////////////////////////////////////////////////////*/
//region Controls showing / hiding
+ @Override
protected void showOrHideButtons() {
super.showOrHideButtons();
@Nullable final PlayQueue playQueue = player.getPlayQueue();
@@ -667,12 +670,11 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
}
animate(binding.itemsListPanel, false, DEFAULT_CONTROLS_DURATION,
- AnimationType.SLIDE_AND_ALPHA, 0, () -> {
+ AnimationType.SLIDE_AND_ALPHA, 0, () ->
// Even when queueLayout is GONE it receives touch events
// and ruins normal behavior of the app. This line fixes it
binding.itemsListPanel.setTranslationY(
- -binding.itemsListPanel.getHeight() * 5);
- });
+ -binding.itemsListPanel.getHeight() * 5.0f));
// clear focus, otherwise a white rectangle remains on top of the player
binding.itemsListClose.clearFocus();
@@ -845,8 +847,7 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
}
PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), player.getPlaybackPitch(),
- player.getPlaybackSkipSilence(), (speed, pitch, skipSilence)
- -> player.setPlaybackParameters(speed, pitch, skipSilence))
+ player.getPlaybackSkipSilence(), player::setPlaybackParameters)
.show(activity.getSupportFragmentManager(), null);
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
index 499800690..9ce04bfd5 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PlayerUi.java
@@ -31,7 +31,7 @@ public abstract class PlayerUi {
/**
* @param player the player instance that will be usable throughout the lifetime of this UI
*/
- public PlayerUi(@NonNull final Player player) {
+ protected PlayerUi(@NonNull final Player player) {
this.context = player.getContext();
this.player = player;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
index 43440b873..8283437f8 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
@@ -1,5 +1,6 @@
package org.schabi.newpipe.player.ui;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static org.schabi.newpipe.MainActivity.DEBUG;
import static org.schabi.newpipe.player.helper.PlayerHelper.buildCloseOverlayLayoutParams;
import static org.schabi.newpipe.player.helper.PlayerHelper.getMinimumVideoHeight;
@@ -140,8 +141,7 @@ public final class PopupPlayerUi extends VideoPlayerUi {
binding.segmentsButton.setVisibility(View.GONE);
binding.moreOptionsButton.setVisibility(View.GONE);
binding.topControls.setOrientation(LinearLayout.HORIZONTAL);
- binding.primaryControls.getLayoutParams().width
- = LinearLayout.LayoutParams.WRAP_CONTENT;
+ binding.primaryControls.getLayoutParams().width = WRAP_CONTENT;
binding.secondaryControls.setAlpha(1.0f);
binding.secondaryControls.setVisibility(View.VISIBLE);
binding.secondaryControls.setTranslationY(0);
@@ -193,14 +193,12 @@ public final class PopupPlayerUi extends VideoPlayerUi {
updateScreenSize();
changePopupSize(popupLayoutParams.width);
checkPopupPositionBounds();
- } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
- // Use only audio source when screen turns off while popup player is playing
- if (player.isPlaying() || player.isLoading()) {
+ } else if (player.isPlaying() || player.isLoading()) {
+ if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
+ // Use only audio source when screen turns off while popup player is playing
player.useVideoSource(false);
- }
- } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
- // Restore video source when screen turns on and user is watching video in popup player
- if (player.isPlaying() || player.isLoading()) {
+ } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
+ // Restore video source when screen turns on and user was watching video in popup
player.useVideoSource(true);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
index 393bf141b..5b0be6f64 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
@@ -41,7 +41,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.view.ContextThemeWrapper;
-import androidx.appcompat.widget.AppCompatImageButton;
import androidx.appcompat.widget.PopupMenu;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
@@ -142,7 +141,7 @@ public abstract class VideoPlayerUi extends PlayerUi
//////////////////////////////////////////////////////////////////////////*/
//region Constructor, setup, destroy
- public VideoPlayerUi(@NonNull final Player player,
+ protected VideoPlayerUi(@NonNull final Player player,
@NonNull final PlayerBinding playerBinding) {
super(player);
binding = playerBinding;
@@ -912,7 +911,20 @@ public abstract class VideoPlayerUi extends PlayerUi
@Override
public void onRepeatModeChanged(@RepeatMode final int repeatMode) {
super.onRepeatModeChanged(repeatMode);
- setRepeatModeButton(binding.repeatButton, repeatMode);
+
+ switch (repeatMode) {
+ case REPEAT_MODE_OFF:
+ binding.repeatButton.setImageResource(R.drawable.exo_controls_repeat_off);
+ break;
+ case REPEAT_MODE_ONE:
+ binding.repeatButton.setImageResource(R.drawable.exo_controls_repeat_one);
+ break;
+ case REPEAT_MODE_ALL:
+ binding.repeatButton.setImageResource(R.drawable.exo_controls_repeat_all);
+ break;
+ default:
+ break; // unreachable
+ }
}
@Override
@@ -927,21 +939,6 @@ public abstract class VideoPlayerUi extends PlayerUi
setMuteButton(isMuted);
}
- private void setRepeatModeButton(final AppCompatImageButton imageButton,
- @RepeatMode final int repeatMode) {
- switch (repeatMode) {
- case REPEAT_MODE_OFF:
- imageButton.setImageResource(R.drawable.exo_controls_repeat_off);
- break;
- case REPEAT_MODE_ONE:
- imageButton.setImageResource(R.drawable.exo_controls_repeat_one);
- break;
- case REPEAT_MODE_ALL:
- imageButton.setImageResource(R.drawable.exo_controls_repeat_all);
- break;
- }
- }
-
private void setMuteButton(final boolean isMuted) {
binding.switchMute.setImageDrawable(AppCompatResources.getDrawable(context, isMuted
? R.drawable.ic_volume_off : R.drawable.ic_volume_up));
@@ -1037,6 +1034,7 @@ public abstract class VideoPlayerUi extends PlayerUi
binding.qualityTextView.setVisibility(View.VISIBLE);
binding.surfaceView.setVisibility(View.VISIBLE);
+ // fallthrough
default:
binding.endScreen.setVisibility(View.GONE);
binding.playbackEndTime.setVisibility(View.VISIBLE);
@@ -1426,8 +1424,6 @@ public abstract class VideoPlayerUi extends PlayerUi
public boolean onKeyDown(final int keyCode) {
switch (keyCode) {
- default:
- break;
case KeyEvent.KEYCODE_BACK:
if (DeviceUtils.isTv(context) && isControlsVisible()) {
hideControls(0, 0);
@@ -1442,7 +1438,7 @@ public abstract class VideoPlayerUi extends PlayerUi
if ((binding.getRoot().hasFocus() && !binding.playbackControlRoot.hasFocus())
|| isAnyListViewOpen()) {
// do not interfere with focus in playlist and play queue etc.
- return false;
+ break;
}
if (player.getCurrentState() == org.schabi.newpipe.player.Player.STATE_BLOCKED) {
@@ -1458,6 +1454,8 @@ public abstract class VideoPlayerUi extends PlayerUi
return true;
}
break;
+ default:
+ break; // ignore other keys
}
return false;
From 1cf746f7216c173194e17b52abb7bac85763cb23 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Thu, 7 Jul 2022 11:09:07 +0200
Subject: [PATCH 039/152] Fix volume gestures not working anymore
---
.../gesture/MainPlayerGestureListener.kt | 55 ++++++++++++-------
.../newpipe/player/ui/MainPlayerUi.java | 7 ++-
2 files changed, 39 insertions(+), 23 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt
index 81e216006..fd7b4ecf0 100644
--- a/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt
@@ -8,11 +8,13 @@ import android.view.View.OnTouchListener
import android.widget.ProgressBar
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
+import androidx.core.view.isVisible
import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.R
import org.schabi.newpipe.ktx.AnimationType
import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.player.Player
+import org.schabi.newpipe.player.helper.AudioReactor
import org.schabi.newpipe.player.helper.PlayerHelper
import org.schabi.newpipe.player.ui.MainPlayerUi
import kotlin.math.abs
@@ -64,22 +66,27 @@ class MainPlayerGestureListener(
}
private fun onScrollVolume(distanceY: Float) {
+ val bar: ProgressBar = binding.volumeProgressBar
+ val audioReactor: AudioReactor = player.audioReactor
+
// If we just started sliding, change the progress bar to match the system volume
- if (binding.volumeRelativeLayout.visibility != View.VISIBLE) {
- val volumePercent: Float =
- player.audioReactor.volume / player.audioReactor.maxVolume.toFloat()
- binding.volumeProgressBar.progress = (volumePercent * MAX_GESTURE_LENGTH).toInt()
+ if (!binding.volumeRelativeLayout.isVisible) {
+ val volumePercent: Float = audioReactor.volume / audioReactor.maxVolume.toFloat()
+ bar.progress = (volumePercent * bar.max).toInt()
}
+ // Update progress bar
binding.volumeProgressBar.incrementProgressBy(distanceY.toInt())
- val currentProgressPercent: Float =
- binding.volumeProgressBar.progress.toFloat() / MAX_GESTURE_LENGTH
- val currentVolume = (player.audioReactor.maxVolume * currentProgressPercent).toInt()
- player.audioReactor.volume = currentVolume
+
+ // Update volume
+ val currentProgressPercent: Float = bar.progress / bar.max.toFloat()
+ val currentVolume = (audioReactor.maxVolume * currentProgressPercent).toInt()
+ audioReactor.volume = currentVolume
if (DEBUG) {
Log.d(TAG, "onScroll().volumeControl, currentVolume = $currentVolume")
}
+ // Update player center image
binding.volumeImageView.setImageDrawable(
AppCompatResources.getDrawable(
player.context,
@@ -92,12 +99,11 @@ class MainPlayerGestureListener(
)
)
- if (binding.volumeRelativeLayout.visibility != View.VISIBLE) {
+ // Make sure the correct layout is visible
+ if (!binding.volumeRelativeLayout.isVisible) {
binding.volumeRelativeLayout.animate(true, 200, AnimationType.SCALE_AND_ALPHA)
}
- if (binding.brightnessRelativeLayout.visibility == View.VISIBLE) {
- binding.volumeRelativeLayout.visibility = View.GONE
- }
+ binding.brightnessRelativeLayout.isVisible = false
}
private fun onScrollBrightness(distanceY: Float) {
@@ -105,9 +111,13 @@ class MainPlayerGestureListener(
val window = parent.window
val layoutParams = window.attributes
val bar: ProgressBar = binding.brightnessProgressBar
+
+ // Update progress bar
val oldBrightness = layoutParams.screenBrightness
bar.progress = (bar.max * max(0f, min(1f, oldBrightness))).toInt()
bar.incrementProgressBy(distanceY.toInt())
+
+ // Update brightness
val currentProgressPercent = bar.progress.toFloat() / bar.max
layoutParams.screenBrightness = currentProgressPercent
window.attributes = layoutParams
@@ -121,26 +131,32 @@ class MainPlayerGestureListener(
"currentBrightness = " + currentProgressPercent
)
}
+
+ // Update player center image
binding.brightnessImageView.setImageDrawable(
AppCompatResources.getDrawable(
player.context,
- if (currentProgressPercent < 0.25) R.drawable.ic_brightness_low else if (currentProgressPercent < 0.75) R.drawable.ic_brightness_medium else R.drawable.ic_brightness_high
+ when {
+ currentProgressPercent < 0.25 -> R.drawable.ic_brightness_low
+ currentProgressPercent < 0.75 -> R.drawable.ic_brightness_medium
+ else -> R.drawable.ic_brightness_high
+ }
)
)
- if (binding.brightnessRelativeLayout.visibility != View.VISIBLE) {
+
+ // Make sure the correct layout is visible
+ if (!binding.brightnessRelativeLayout.isVisible) {
binding.brightnessRelativeLayout.animate(true, 200, AnimationType.SCALE_AND_ALPHA)
}
- if (binding.volumeRelativeLayout.visibility == View.VISIBLE) {
- binding.volumeRelativeLayout.visibility = View.GONE
- }
+ binding.volumeRelativeLayout.isVisible = false
}
override fun onScrollEnd(event: MotionEvent) {
super.onScrollEnd(event)
- if (binding.volumeRelativeLayout.visibility == View.VISIBLE) {
+ if (binding.volumeRelativeLayout.isVisible) {
binding.volumeRelativeLayout.animate(false, 200, AnimationType.SCALE_AND_ALPHA, 200)
}
- if (binding.brightnessRelativeLayout.visibility == View.VISIBLE) {
+ if (binding.brightnessRelativeLayout.isVisible) {
binding.brightnessRelativeLayout.animate(false, 200, AnimationType.SCALE_AND_ALPHA, 200)
}
}
@@ -210,7 +226,6 @@ class MainPlayerGestureListener(
private val TAG = MainPlayerGestureListener::class.java.simpleName
private val DEBUG = MainActivity.DEBUG
private const val MOVEMENT_THRESHOLD = 40
- const val MAX_GESTURE_LENGTH = 0.75f
private fun getNavigationBarHeight(context: Context): Int {
val resId = context.resources
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
index eebcc81c4..d9f5ea7f4 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
@@ -520,12 +520,13 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
public void onLayoutChange(final View view, final int l, final int t, final int r, final int b,
final int ol, final int ot, final int or, final int ob) {
if (l != ol || t != ot || r != or || b != ob) {
- // Use smaller value to be consistent between screen orientations
- // (and to make usage easier)
+ // Use a smaller value to be consistent across screen orientations, and to make usage
+ // easier. Multiply by 3/4 to ensure the user does not need to move the finger up to the
+ // screen border, in order to reach the maximum volume/brightness.
final int width = r - l;
final int height = b - t;
final int min = Math.min(width, height);
- final int maxGestureLength = (int) (min * MainPlayerGestureListener.MAX_GESTURE_LENGTH);
+ final int maxGestureLength = (int) (min * 0.75);
if (DEBUG) {
Log.d(TAG, "maxGestureLength = " + maxGestureLength);
From 9c51fc3adeaac4670da0bead156315b286f8b5c3 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Thu, 7 Jul 2022 11:59:00 +0200
Subject: [PATCH 040/152] Move functions to get Android dimen to ThemeHelper
---
.../gesture/MainPlayerGestureListener.kt | 28 ++++++-------------
.../org/schabi/newpipe/util/ThemeHelper.java | 16 +++++++++++
2 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt
index fd7b4ecf0..095b3ccdb 100644
--- a/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt
@@ -1,6 +1,5 @@
package org.schabi.newpipe.player.gesture
-import android.content.Context
import android.util.Log
import android.view.MotionEvent
import android.view.View
@@ -17,6 +16,7 @@ import org.schabi.newpipe.player.Player
import org.schabi.newpipe.player.helper.AudioReactor
import org.schabi.newpipe.player.helper.PlayerHelper
import org.schabi.newpipe.player.ui.MainPlayerUi
+import org.schabi.newpipe.util.ThemeHelper.getAndroidDimenPx
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@@ -172,9 +172,13 @@ class MainPlayerGestureListener(
return false
}
- val isTouchingStatusBar: Boolean = initialEvent.y < getStatusBarHeight(player.context)
- val isTouchingNavigationBar: Boolean =
- initialEvent.y > (binding.root.height - getNavigationBarHeight(player.context))
+ // Calculate heights of status and navigation bars
+ val statusBarHeight = getAndroidDimenPx(player.context, "status_bar_height")
+ val navigationBarHeight = getAndroidDimenPx(player.context, "navigation_bar_height")
+
+ // Do not handle this event if initially it started from status or navigation bars
+ val isTouchingStatusBar = initialEvent.y < statusBarHeight
+ val isTouchingNavigationBar = initialEvent.y > (binding.root.height - navigationBarHeight)
if (isTouchingStatusBar || isTouchingNavigationBar) {
return false
}
@@ -226,21 +230,5 @@ class MainPlayerGestureListener(
private val TAG = MainPlayerGestureListener::class.java.simpleName
private val DEBUG = MainActivity.DEBUG
private const val MOVEMENT_THRESHOLD = 40
-
- private fun getNavigationBarHeight(context: Context): Int {
- val resId = context.resources
- .getIdentifier("navigation_bar_height", "dimen", "android")
- return if (resId > 0) {
- context.resources.getDimensionPixelSize(resId)
- } else 0
- }
-
- private fun getStatusBarHeight(context: Context): Int {
- val resId = context.resources
- .getIdentifier("status_bar_height", "dimen", "android")
- return if (resId > 0) {
- context.resources.getDimensionPixelSize(resId)
- } else 0
- }
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
index b8e3a86ed..389af80ee 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
@@ -244,6 +244,22 @@ public final class ThemeHelper {
return AppCompatResources.getDrawable(context, typedValue.resourceId);
}
+ /**
+ * Gets a runtime dimen from the {@code android} package. Should be used for dimens for which
+ * normal accessing with {@code R.dimen.} is not available.
+ *
+ * @param context context
+ * @param name dimen resource name (e.g. navigation_bar_height)
+ * @return the obtained dimension, in pixels, or 0 if the resource could not be resolved
+ */
+ public static int getAndroidDimenPx(@NonNull final Context context, final String name) {
+ final int resId = context.getResources().getIdentifier(name, "dimen", "android");
+ if (resId <= 0) {
+ return 0;
+ }
+ return context.getResources().getDimensionPixelSize(resId);
+ }
+
private static String getSelectedThemeKey(final Context context) {
final String themeKey = context.getString(R.string.theme_key);
final String defaultTheme = context.getResources().getString(R.string.default_theme_value);
From 3692858a3d10fb33d0386149d630264ca93eca23 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Fri, 8 Jul 2022 22:33:35 +0200
Subject: [PATCH 041/152] Move popup layout param to PopupPlayerUi
---
.../gesture/PopupPlayerGestureListener.kt | 71 +++++------
.../newpipe/player/helper/PlayerHelper.java | 103 +---------------
.../newpipe/player/ui/PopupPlayerUi.java | 110 +++++++++++++++++-
3 files changed, 144 insertions(+), 140 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/PopupPlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/PopupPlayerGestureListener.kt
index b8c1bc54c..bda6ee8d1 100644
--- a/app/src/main/java/org/schabi/newpipe/player/gesture/PopupPlayerGestureListener.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/gesture/PopupPlayerGestureListener.kt
@@ -7,7 +7,6 @@ import android.view.ViewConfiguration
import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.ktx.AnimationType
import org.schabi.newpipe.ktx.animate
-import org.schabi.newpipe.player.helper.PlayerHelper
import org.schabi.newpipe.player.ui.PopupPlayerUi
import kotlin.math.abs
import kotlin.math.hypot
@@ -87,7 +86,7 @@ class PopupPlayerGestureListener(
player.changeState(player.currentState)
}
if (!playerUi.isPopupClosing) {
- PlayerHelper.savePopupPositionAndSizeToPrefs(playerUi)
+ playerUi.savePopupPositionAndSizeToPrefs()
}
}
@@ -106,40 +105,42 @@ class PopupPlayerGestureListener(
}
private fun handleMultiDrag(event: MotionEvent): Boolean {
- if (initPointerDistance != -1.0 && event.pointerCount == 2) {
- // get the movements of the fingers
- val firstPointerMove = hypot(
- event.getX(0) - initFirstPointerX.toDouble(),
- event.getY(0) - initFirstPointerY.toDouble()
- )
- val secPointerMove = hypot(
- event.getX(1) - initSecPointerX.toDouble(),
- event.getY(1) - initSecPointerY.toDouble()
- )
-
- // minimum threshold beyond which pinch gesture will work
- val minimumMove = ViewConfiguration.get(player.context).scaledTouchSlop
-
- if (max(firstPointerMove, secPointerMove) > minimumMove) {
- // calculate current distance between the pointers
- val currentPointerDistance = hypot(
- event.getX(0) - event.getX(1).toDouble(),
- event.getY(0) - event.getY(1).toDouble()
- )
-
- val popupWidth = playerUi.popupLayoutParams.width.toDouble()
- // change co-ordinates of popup so the center stays at the same position
- val newWidth = popupWidth * currentPointerDistance / initPointerDistance
- initPointerDistance = currentPointerDistance
- playerUi.popupLayoutParams.x += ((popupWidth - newWidth) / 2.0).toInt()
-
- playerUi.checkPopupPositionBounds()
- playerUi.updateScreenSize()
- playerUi.changePopupSize(min(playerUi.screenWidth.toDouble(), newWidth).toInt())
- return true
- }
+ if (initPointerDistance == -1.0 || event.pointerCount != 2) {
+ return false
}
- return false
+
+ // get the movements of the fingers
+ val firstPointerMove = hypot(
+ event.getX(0) - initFirstPointerX.toDouble(),
+ event.getY(0) - initFirstPointerY.toDouble()
+ )
+ val secPointerMove = hypot(
+ event.getX(1) - initSecPointerX.toDouble(),
+ event.getY(1) - initSecPointerY.toDouble()
+ )
+
+ // minimum threshold beyond which pinch gesture will work
+ val minimumMove = ViewConfiguration.get(player.context).scaledTouchSlop
+ if (max(firstPointerMove, secPointerMove) <= minimumMove) {
+ return false
+ }
+
+ // calculate current distance between the pointers
+ val currentPointerDistance = hypot(
+ event.getX(0) - event.getX(1).toDouble(),
+ event.getY(0) - event.getY(1).toDouble()
+ )
+
+ val popupWidth = playerUi.popupLayoutParams.width.toDouble()
+ // change co-ordinates of popup so the center stays at the same position
+ val newWidth = popupWidth * currentPointerDistance / initPointerDistance
+ initPointerDistance = currentPointerDistance
+ playerUi.popupLayoutParams.x += ((popupWidth - newWidth) / 2.0).toInt()
+
+ playerUi.checkPopupPositionBounds()
+ playerUi.updateScreenSize()
+ playerUi.changePopupSize(min(playerUi.screenWidth.toDouble(), newWidth).toInt())
+ return true
}
private fun onPopupResizingStart() {
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index ec4cf8602..d1d29dd71 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -10,19 +10,13 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLA
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP;
-import static org.schabi.newpipe.player.ui.PopupPlayerUi.IDLE_WINDOW_FLAGS;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.graphics.PixelFormat;
-import android.os.Build;
import android.provider.Settings;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.view.WindowManager;
import android.view.accessibility.CaptioningManager;
import androidx.annotation.IntDef;
@@ -49,12 +43,11 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.utils.Utils;
-import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.Player;
+import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
-import org.schabi.newpipe.player.ui.PopupPlayerUi;
import org.schabi.newpipe.util.ListHelper;
import java.lang.annotation.Retention;
@@ -77,20 +70,6 @@ public final class PlayerHelper {
private static final NumberFormat SPEED_FORMATTER = new DecimalFormat("0.##x");
private static final NumberFormat PITCH_FORMATTER = new DecimalFormat("##%");
- /**
- * Maximum opacity allowed for Android 12 and higher to allow touches on other apps when using
- * NewPipe's popup player.
- *
- *
- * This value is hardcoded instead of being get dynamically with the method linked of the
- * constant documentation below, because it is not static and popup player layout parameters
- * are generated with static methods.
- *
- *
- * @see WindowManager.LayoutParams#FLAG_NOT_TOUCHABLE
- */
- private static final float MAXIMUM_OPACITY_ALLOWED_FOR_S_AND_HIGHER = 0.8f;
-
@Retention(SOURCE)
@IntDef({AUTOPLAY_TYPE_ALWAYS, AUTOPLAY_TYPE_WIFI,
AUTOPLAY_TYPE_NEVER})
@@ -525,90 +504,10 @@ public final class PlayerHelper {
.apply();
}
- /**
- * @param playerUi {@code screenWidth} and {@code screenHeight} must have been initialized
- * @return the popup starting layout params
- */
- @SuppressLint("RtlHardcoded")
- public static WindowManager.LayoutParams retrievePopupLayoutParamsFromPrefs(
- final PopupPlayerUi playerUi) {
- final SharedPreferences prefs = playerUi.getPlayer().getPrefs();
- final Context context = playerUi.getPlayer().getContext();
-
- final boolean popupRememberSizeAndPos = prefs.getBoolean(
- context.getString(R.string.popup_remember_size_pos_key), true);
- final float defaultSize = context.getResources().getDimension(R.dimen.popup_default_width);
- final float popupWidth = popupRememberSizeAndPos
- ? prefs.getFloat(context.getString(R.string.popup_saved_width_key), defaultSize)
- : defaultSize;
- final float popupHeight = getMinimumVideoHeight(popupWidth);
-
- final WindowManager.LayoutParams popupLayoutParams = new WindowManager.LayoutParams(
- (int) popupWidth, (int) popupHeight,
- popupLayoutParamType(),
- IDLE_WINDOW_FLAGS,
- PixelFormat.TRANSLUCENT);
- popupLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
- popupLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-
- final int centerX = (int) (playerUi.getScreenWidth() / 2f - popupWidth / 2f);
- final int centerY = (int) (playerUi.getScreenHeight() / 2f - popupHeight / 2f);
- popupLayoutParams.x = popupRememberSizeAndPos
- ? prefs.getInt(context.getString(R.string.popup_saved_x_key), centerX) : centerX;
- popupLayoutParams.y = popupRememberSizeAndPos
- ? prefs.getInt(context.getString(R.string.popup_saved_y_key), centerY) : centerY;
-
- return popupLayoutParams;
- }
-
- public static void savePopupPositionAndSizeToPrefs(final PopupPlayerUi playerUi) {
- if (playerUi.getPopupLayoutParams() != null) {
- final Context context = playerUi.getPlayer().getContext();
- playerUi.getPlayer().getPrefs().edit()
- .putFloat(context.getString(R.string.popup_saved_width_key),
- playerUi.getPopupLayoutParams().width)
- .putInt(context.getString(R.string.popup_saved_x_key),
- playerUi.getPopupLayoutParams().x)
- .putInt(context.getString(R.string.popup_saved_y_key),
- playerUi.getPopupLayoutParams().y)
- .apply();
- }
- }
-
public static float getMinimumVideoHeight(final float width) {
return width / (16.0f / 9.0f); // Respect the 16:9 ratio that most videos have
}
- @SuppressLint("RtlHardcoded")
- public static WindowManager.LayoutParams buildCloseOverlayLayoutParams() {
- final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-
- final WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
- popupLayoutParamType(),
- flags,
- PixelFormat.TRANSLUCENT);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- // Setting maximum opacity allowed for touch events to other apps for Android 12 and
- // higher to prevent non interaction when using other apps with the popup player
- closeOverlayLayoutParams.alpha = MAXIMUM_OPACITY_ALLOWED_FOR_S_AND_HIGHER;
- }
-
- closeOverlayLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
- closeOverlayLayoutParams.softInputMode =
- WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
- return closeOverlayLayoutParams;
- }
-
- public static int popupLayoutParamType() {
- return Build.VERSION.SDK_INT < Build.VERSION_CODES.O
- ? WindowManager.LayoutParams.TYPE_PHONE
- : WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
- }
-
public static int retrieveSeekDurationFromPreferences(final Player player) {
return Integer.parseInt(Objects.requireNonNull(player.getPrefs().getString(
player.getContext().getString(R.string.seek_duration_key),
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
index 8283437f8..46396a840 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
@@ -2,21 +2,25 @@ package org.schabi.newpipe.player.ui;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static org.schabi.newpipe.MainActivity.DEBUG;
-import static org.schabi.newpipe.player.helper.PlayerHelper.buildCloseOverlayLayoutParams;
import static org.schabi.newpipe.player.helper.PlayerHelper.getMinimumVideoHeight;
-import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePopupLayoutParamsFromPrefs;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
+import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.PixelFormat;
+import android.os.Build;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AnticipateInterpolator;
import android.widget.LinearLayout;
@@ -38,6 +42,20 @@ import org.schabi.newpipe.player.helper.PlayerHelper;
public final class PopupPlayerUi extends VideoPlayerUi {
private static final String TAG = PopupPlayerUi.class.getSimpleName();
+ /**
+ * Maximum opacity allowed for Android 12 and higher to allow touches on other apps when using
+ * NewPipe's popup player.
+ *
+ *
+ * This value is hardcoded instead of being get dynamically with the method linked of the
+ * constant documentation below, because it is not static and popup player layout parameters
+ * are generated with static methods.
+ *
+ *
+ * @see WindowManager.LayoutParams#FLAG_NOT_TOUCHABLE
+ */
+ private static final float MAXIMUM_OPACITY_ALLOWED_FOR_S_AND_HIGHER = 0.8f;
+
/*//////////////////////////////////////////////////////////////////////////
// Popup player
//////////////////////////////////////////////////////////////////////////*/
@@ -98,7 +116,7 @@ public final class PopupPlayerUi extends VideoPlayerUi {
updateScreenSize();
- popupLayoutParams = retrievePopupLayoutParamsFromPrefs(this);
+ popupLayoutParams = retrievePopupLayoutParamsFromPrefs();
binding.surfaceView.setHeights(popupLayoutParams.height, popupLayoutParams.height);
checkPopupPositionBounds();
@@ -446,6 +464,92 @@ public final class PopupPlayerUi extends VideoPlayerUi {
//endregion
+ /*//////////////////////////////////////////////////////////////////////////
+ // Popup & closing overlay layout params + saving popup position and size
+ //////////////////////////////////////////////////////////////////////////*/
+ //region Popup & closing overlay layout params + saving popup position and size
+
+ /**
+ * {@code screenWidth} and {@code screenHeight} must have been initialized.
+ * @return the popup starting layout params
+ */
+ @SuppressLint("RtlHardcoded")
+ public WindowManager.LayoutParams retrievePopupLayoutParamsFromPrefs() {
+ final SharedPreferences prefs = getPlayer().getPrefs();
+ final Context context = getPlayer().getContext();
+
+ final boolean popupRememberSizeAndPos = prefs.getBoolean(
+ context.getString(R.string.popup_remember_size_pos_key), true);
+ final float defaultSize = context.getResources().getDimension(R.dimen.popup_default_width);
+ final float popupWidth = popupRememberSizeAndPos
+ ? prefs.getFloat(context.getString(R.string.popup_saved_width_key), defaultSize)
+ : defaultSize;
+ final float popupHeight = getMinimumVideoHeight(popupWidth);
+
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ (int) popupWidth, (int) popupHeight,
+ popupLayoutParamType(),
+ IDLE_WINDOW_FLAGS,
+ PixelFormat.TRANSLUCENT);
+ params.gravity = Gravity.LEFT | Gravity.TOP;
+ params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+
+ final int centerX = (int) (screenWidth / 2f - popupWidth / 2f);
+ final int centerY = (int) (screenHeight / 2f - popupHeight / 2f);
+ params.x = popupRememberSizeAndPos
+ ? prefs.getInt(context.getString(R.string.popup_saved_x_key), centerX) : centerX;
+ params.y = popupRememberSizeAndPos
+ ? prefs.getInt(context.getString(R.string.popup_saved_y_key), centerY) : centerY;
+
+ return params;
+ }
+
+ public void savePopupPositionAndSizeToPrefs() {
+ if (getPopupLayoutParams() != null) {
+ final Context context = getPlayer().getContext();
+ getPlayer().getPrefs().edit()
+ .putFloat(context.getString(R.string.popup_saved_width_key),
+ popupLayoutParams.width)
+ .putInt(context.getString(R.string.popup_saved_x_key),
+ popupLayoutParams.x)
+ .putInt(context.getString(R.string.popup_saved_y_key),
+ popupLayoutParams.y)
+ .apply();
+ }
+ }
+
+ @SuppressLint("RtlHardcoded")
+ public static WindowManager.LayoutParams buildCloseOverlayLayoutParams() {
+ final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+
+ final WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
+ popupLayoutParamType(),
+ flags,
+ PixelFormat.TRANSLUCENT);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ // Setting maximum opacity allowed for touch events to other apps for Android 12 and
+ // higher to prevent non interaction when using other apps with the popup player
+ closeOverlayLayoutParams.alpha = MAXIMUM_OPACITY_ALLOWED_FOR_S_AND_HIGHER;
+ }
+
+ closeOverlayLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ closeOverlayLayoutParams.softInputMode =
+ WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+ return closeOverlayLayoutParams;
+ }
+
+ public static int popupLayoutParamType() {
+ return Build.VERSION.SDK_INT < Build.VERSION_CODES.O
+ ? WindowManager.LayoutParams.TYPE_PHONE
+ : WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ }
+ //endregion
+
+
/*//////////////////////////////////////////////////////////////////////////
// Getters
//////////////////////////////////////////////////////////////////////////*/
From 61c1da144e4b0a824d4816d9ecad6a59b53d9cf3 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Sat, 9 Jul 2022 17:17:30 +0200
Subject: [PATCH 042/152] Some refactorings after review comments
---
.../fragments/detail/VideoDetailFragment.java | 11 +++--
.../newpipe/local/dialog/PlaylistDialog.java | 2 +-
.../schabi/newpipe/player/PlayerService.java | 23 ++++-----
.../newpipe/player/ui/MainPlayerUi.java | 47 ++++++++-----------
.../newpipe/player/ui/VideoPlayerUi.java | 19 +++-----
5 files changed, 42 insertions(+), 60 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 8ffff2f9e..5dc6bb436 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
@@ -1311,11 +1311,12 @@ public final class VideoDetailFragment
setHeightThumbnail();
// Prevent from re-adding a view multiple times
- new Handler().post(() -> player.UIs().get(MainPlayerUi.class).ifPresent(playerUi -> {
- playerUi.removeViewFromParent();
- binding.playerPlaceholder.addView(playerUi.getBinding().getRoot());
- playerUi.setupVideoSurfaceIfNeeded();
- }));
+ new Handler(Looper.getMainLooper()).post(() ->
+ player.UIs().get(MainPlayerUi.class).ifPresent(playerUi -> {
+ playerUi.removeViewFromParent();
+ binding.playerPlaceholder.addView(playerUi.getBinding().getRoot());
+ playerUi.setupVideoSurfaceIfNeeded();
+ }));
}
private void removeVideoPlayerView() {
diff --git a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java
index dec8b05b2..612c38181 100644
--- a/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java
+++ b/app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistDialog.java
@@ -168,7 +168,7 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
final List streamEntities = Stream.of(player.getPlayQueue())
.filter(Objects::nonNull)
- .flatMap(playQueue -> Objects.requireNonNull(playQueue).getStreams().stream())
+ .flatMap(playQueue -> playQueue.getStreams().stream())
.map(StreamEntity::new)
.collect(Collectors.toList());
if (streamEntities.isEmpty()) {
diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
index 326b01590..14e8262d6 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
@@ -33,8 +33,6 @@ import org.schabi.newpipe.util.ThemeHelper;
/**
* One service for all players.
- *
- * @author mauriciocolli
*/
public final class PlayerService extends Service {
private static final String TAG = PlayerService.class.getSimpleName();
@@ -72,14 +70,16 @@ public final class PlayerService extends Service {
+ "], flags = [" + flags + "], startId = [" + startId + "]");
}
- if (!Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
- || player.getPlayQueue() != null) {
- // ^ no need to process media button's action if player is not working
+ if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
+ && player.getPlayQueue() == null) {
+ // No need to process media button's actions if the player is not working, otherwise the
+ // player service would strangely start with nothing to play
+ return START_NOT_STICKY;
+ }
- player.handleIntent(intent);
- if (player.getMediaSessionManager() != null) {
- player.getMediaSessionManager().handleMediaButtonIntent(intent);
- }
+ player.handleIntent(intent);
+ if (player.getMediaSessionManager() != null) {
+ player.getMediaSessionManager().handleMediaButtonIntent(intent);
}
return START_NOT_STICKY;
@@ -97,11 +97,6 @@ public final class PlayerService extends Service {
// We can't just pause the player here because it will make transition
// from one stream to a new stream not smooth
player.smoothStopForImmediateReusing();
-
- // Notification shows information about old stream but if a user selects
- // a stream from backStack it's not actual anymore
- // So we should hide the notification at all.
- // When autoplay enabled such notification flashing is annoying so skip this case
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
index d9f5ea7f4..278e4f1ff 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
@@ -75,6 +75,11 @@ import java.util.Optional;
public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutChangeListener {
private static final String TAG = MainPlayerUi.class.getSimpleName();
+ // see the Javadoc of calculateMaxEndScreenThumbnailHeight for information
+ private static final int DETAIL_ROOT_MINIMUM_HEIGHT = 85; // dp
+ private static final int DETAIL_TITLE_TEXT_SIZE_TV = 16; // sp
+ private static final int DETAIL_TITLE_TEXT_SIZE_TABLET = 15; // sp
+
private boolean isFullscreen = false;
private boolean isVerticalVideo = false;
private boolean fragmentIsVisible = false;
@@ -262,13 +267,8 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
binding.topControls.setClickable(true);
binding.topControls.setFocusable(true);
- if (isFullscreen) {
- binding.titleTextView.setVisibility(View.VISIBLE);
- binding.channelTextView.setVisibility(View.VISIBLE);
- } else {
- binding.titleTextView.setVisibility(View.GONE);
- binding.channelTextView.setVisibility(View.GONE);
- }
+ binding.titleTextView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
+ binding.channelTextView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
}
@Override
@@ -450,13 +450,12 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
* The calculating follows these rules:
*
* -
- * Show at least stream title and content creator on TVs and tablets
- * when in landscape (always the case for TVs) and not in fullscreen mode.
- * This requires to have at least
85dp
free space for {@link R.id.detail_root}
- * and additional space for the stream title text size
- * ({@link R.id.detail_title_root_layout}).
- * The text size is 15sp
on tablets and 16sp
on TVs,
- * see {@link R.id.titleTextView}.
+ * Show at least stream title and content creator on TVs and tablets when in landscape
+ * (always the case for TVs) and not in fullscreen mode. This requires to have at least
+ * {@link #DETAIL_ROOT_MINIMUM_HEIGHT} free space for {@link R.id.detail_root} and
+ * additional space for the stream title text size ({@link R.id.detail_title_root_layout}).
+ * The text size is {@link #DETAIL_TITLE_TEXT_SIZE_TABLET} on tablets and
+ * {@link #DETAIL_TITLE_TEXT_SIZE_TV} on TVs, see {@link R.id.titleTextView}.
*
* -
* Otherwise, the max thumbnail height is the screen height.
@@ -472,12 +471,12 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
final int screenHeight = context.getResources().getDisplayMetrics().heightPixels;
if (DeviceUtils.isTv(context) && !isFullscreen()) {
- final int videoInfoHeight =
- DeviceUtils.dpToPx(85, context) + DeviceUtils.spToPx(16, context);
+ final int videoInfoHeight = DeviceUtils.dpToPx(DETAIL_ROOT_MINIMUM_HEIGHT, context)
+ + DeviceUtils.spToPx(DETAIL_TITLE_TEXT_SIZE_TV, context);
return Math.min(bitmap.getHeight(), screenHeight - videoInfoHeight);
} else if (DeviceUtils.isTablet(context) && isLandscape() && !isFullscreen()) {
- final int videoInfoHeight =
- DeviceUtils.dpToPx(85, context) + DeviceUtils.spToPx(15, context);
+ final int videoInfoHeight = DeviceUtils.dpToPx(DETAIL_ROOT_MINIMUM_HEIGHT, context)
+ + DeviceUtils.spToPx(DETAIL_TITLE_TEXT_SIZE_TABLET, context);
return Math.min(bitmap.getHeight(), screenHeight - videoInfoHeight);
} else { // fullscreen player: max height is the device height
return Math.min(bitmap.getHeight(), screenHeight);
@@ -933,15 +932,9 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
}
fragmentListener.onFullscreenStateChanged(isFullscreen);
- if (isFullscreen) {
- binding.titleTextView.setVisibility(View.VISIBLE);
- binding.channelTextView.setVisibility(View.VISIBLE);
- binding.playerCloseButton.setVisibility(View.GONE);
- } else {
- binding.titleTextView.setVisibility(View.GONE);
- binding.channelTextView.setVisibility(View.GONE);
- binding.playerCloseButton.setVisibility(View.VISIBLE);
- }
+ binding.titleTextView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
+ binding.channelTextView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
+ binding.playerCloseButton.setVisibility(isFullscreen ? View.GONE : View.VISIBLE);
setupScreenRotationButton();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
index 5b0be6f64..4d1065112 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
@@ -1,7 +1,6 @@
package org.schabi.newpipe.player.ui;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
-import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
import static org.schabi.newpipe.MainActivity.DEBUG;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
@@ -912,18 +911,12 @@ public abstract class VideoPlayerUi extends PlayerUi
public void onRepeatModeChanged(@RepeatMode final int repeatMode) {
super.onRepeatModeChanged(repeatMode);
- switch (repeatMode) {
- case REPEAT_MODE_OFF:
- binding.repeatButton.setImageResource(R.drawable.exo_controls_repeat_off);
- break;
- case REPEAT_MODE_ONE:
- binding.repeatButton.setImageResource(R.drawable.exo_controls_repeat_one);
- break;
- case REPEAT_MODE_ALL:
- binding.repeatButton.setImageResource(R.drawable.exo_controls_repeat_all);
- break;
- default:
- break; // unreachable
+ if (repeatMode == REPEAT_MODE_ALL) {
+ binding.repeatButton.setImageResource(R.drawable.exo_controls_repeat_all);
+ } else if (repeatMode == REPEAT_MODE_ONE) {
+ binding.repeatButton.setImageResource(R.drawable.exo_controls_repeat_one);
+ } else /* repeatMode == REPEAT_MODE_OFF */ {
+ binding.repeatButton.setImageResource(R.drawable.exo_controls_repeat_off);
}
}
From c03eac1dc99e9e61b863b5984444407dc8ee13a2 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Sat, 9 Jul 2022 17:50:12 +0200
Subject: [PATCH 043/152] Some SonarLint refactors
---
.../player/gesture/BasePlayerGestureListener.kt | 3 ++-
.../newpipe/player/gesture/DoubleTapListener.kt | 6 +++---
.../org/schabi/newpipe/player/ui/MainPlayerUi.java | 11 +++++------
.../org/schabi/newpipe/player/ui/PopupPlayerUi.java | 3 +--
.../org/schabi/newpipe/player/ui/VideoPlayerUi.java | 3 ++-
5 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt
index b006e73aa..555c34f96 100644
--- a/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/gesture/BasePlayerGestureListener.kt
@@ -1,6 +1,7 @@
package org.schabi.newpipe.player.gesture
import android.os.Handler
+import android.os.Looper
import android.util.Log
import android.view.GestureDetector
import android.view.MotionEvent
@@ -130,7 +131,7 @@ abstract class BasePlayerGestureListener(
}
private var doubleTapDelay = DOUBLE_TAP_DELAY
- private val doubleTapHandler: Handler = Handler()
+ private val doubleTapHandler: Handler = Handler(Looper.getMainLooper())
private val doubleTapRunnable = Runnable {
if (DEBUG)
Log.d(TAG, "doubleTapRunnable called")
diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/DoubleTapListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/DoubleTapListener.kt
index 1a0b141e6..fc026abd9 100644
--- a/app/src/main/java/org/schabi/newpipe/player/gesture/DoubleTapListener.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/gesture/DoubleTapListener.kt
@@ -1,7 +1,7 @@
package org.schabi.newpipe.player.gesture
interface DoubleTapListener {
- fun onDoubleTapStarted(portion: DisplayPortion) {}
- fun onDoubleTapProgressDown(portion: DisplayPortion) {}
- fun onDoubleTapFinished() {}
+ fun onDoubleTapStarted(portion: DisplayPortion)
+ fun onDoubleTapProgressDown(portion: DisplayPortion)
+ fun onDoubleTapFinished()
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
index 278e4f1ff..52a486add 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
@@ -1,5 +1,6 @@
package org.schabi.newpipe.player.ui;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static org.schabi.newpipe.MainActivity.DEBUG;
import static org.schabi.newpipe.QueueItemMenuUtil.openPopupMenu;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
@@ -21,6 +22,7 @@ import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -156,7 +158,7 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
.ifPresent(fragmentManager ->
PlaylistDialog.showForPlayQueue(player, fragmentManager)));
- settingsContentObserver = new ContentObserver(new Handler()) {
+ settingsContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(final boolean selfChange) {
setupScreenRotationButton();
@@ -237,8 +239,7 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
private void initVideoPlayer() {
// restore last resize mode
setResizeMode(PlayerHelper.retrieveResizeModeFromPrefs(player));
- binding.getRoot().setLayoutParams(new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
+ binding.getRoot().setLayoutParams(new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
@Override
@@ -253,8 +254,7 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
binding.getRoot().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
binding.moreOptionsButton.setVisibility(View.VISIBLE);
binding.topControls.setOrientation(LinearLayout.VERTICAL);
- binding.primaryControls.getLayoutParams().width
- = LinearLayout.LayoutParams.MATCH_PARENT;
+ binding.primaryControls.getLayoutParams().width = MATCH_PARENT;
binding.secondaryControls.setVisibility(View.INVISIBLE);
binding.moreOptionsButton.setImageDrawable(AppCompatResources.getDrawable(context,
R.drawable.ic_expand_more));
@@ -459,7 +459,6 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
*
* -
* Otherwise, the max thumbnail height is the screen height.
- * TODO investigate why this is done on popup player, too
*
*
*
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
index 46396a840..bb810f86b 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
@@ -287,8 +287,7 @@ public final class PopupPlayerUi extends VideoPlayerUi {
}
final float minimumWidth = context.getResources().getDimension(R.dimen.popup_minimum_width);
- final int actualWidth = (int) (width > screenWidth ? screenWidth
- : (width < minimumWidth ? minimumWidth : width));
+ final int actualWidth = Math.min((int) Math.max(width, minimumWidth), screenWidth);
final int actualHeight = (int) getMinimumVideoHeight(width);
if (DEBUG) {
Log.d(TAG, "updatePopupSize() updated values:"
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
index 4d1065112..bdb327df1 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
@@ -25,6 +25,7 @@ import android.graphics.PorterDuffColorFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
@@ -103,7 +104,7 @@ public abstract class VideoPlayerUi extends PlayerUi
//////////////////////////////////////////////////////////////////////////*/
protected PlayerBinding binding;
- private final Handler controlsVisibilityHandler = new Handler();
+ private final Handler controlsVisibilityHandler = new Handler(Looper.getMainLooper());
@Nullable private SurfaceHolderCallback surfaceHolderCallback;
boolean surfaceIsSetup = false;
@Nullable private Bitmap thumbnail = null;
From 4443c908cb203e97df5e2624c34681aea2cfe129 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Sat, 9 Jul 2022 17:58:03 +0200
Subject: [PATCH 044/152] Fix SonarLint java:S5320, restrict broadcasts to app
package
---
.../java/org/schabi/newpipe/player/ui/VideoPlayerUi.java | 5 ++++-
.../settings/custom/NotificationActionsPreference.java | 5 ++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
index bdb327df1..d38c8cfe4 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
@@ -57,6 +57,7 @@ import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.ui.CaptionStyleCompat;
import com.google.android.exoplayer2.video.VideoSize;
+import org.schabi.newpipe.App;
import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.PlayerBinding;
import org.schabi.newpipe.extractor.MediaFormat;
@@ -1372,7 +1373,9 @@ public abstract class VideoPlayerUi extends PlayerUi
} else if (v.getId() == binding.switchMute.getId()) {
player.toggleMute();
} else if (v.getId() == binding.playerCloseButton.getId()) {
- context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER));
+ // set package to this app's package to prevent the intent from being seen outside
+ context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER)
+ .setPackage(App.PACKAGE_NAME));
} else if (v.getId() == binding.playbackSpeed.getId()) {
onPlaybackSpeedClicked();
} else if (v.getId() == binding.qualityTextView.getId()) {
diff --git a/app/src/main/java/org/schabi/newpipe/settings/custom/NotificationActionsPreference.java b/app/src/main/java/org/schabi/newpipe/settings/custom/NotificationActionsPreference.java
index b4f6d598a..03b5a5a95 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/custom/NotificationActionsPreference.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/custom/NotificationActionsPreference.java
@@ -25,6 +25,7 @@ import androidx.core.graphics.drawable.DrawableCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
+import org.schabi.newpipe.App;
import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
@@ -62,7 +63,9 @@ public class NotificationActionsPreference extends Preference {
public void onDetached() {
super.onDetached();
saveChanges();
- getContext().sendBroadcast(new Intent(ACTION_RECREATE_NOTIFICATION));
+ // set package to this app's package to prevent the intent from being seen outside
+ getContext().sendBroadcast(new Intent(ACTION_RECREATE_NOTIFICATION)
+ .setPackage(App.PACKAGE_NAME));
}
From 8187a3bc04704e8b1cc380ccbf0c0274a4514494 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Sun, 10 Jul 2022 23:05:37 +0200
Subject: [PATCH 045/152] Move PlayerType into its own class and add
documentation
Also replace some `isPlayerOpen` with direct `playerType == null` checks.
---
.../org/schabi/newpipe/RouterActivity.java | 6 ++--
.../fragments/detail/VideoDetailFragment.java | 2 +-
.../list/channel/ChannelFragment.java | 2 +-
.../list/playlist/PlaylistFragment.java | 2 +-
.../local/playlist/LocalPlaylistFragment.java | 2 +-
.../org/schabi/newpipe/player/Player.java | 4 +--
.../schabi/newpipe/player/PlayerService.java | 5 ---
.../org/schabi/newpipe/player/PlayerType.java | 32 +++++++++++++++++++
.../newpipe/player/helper/PlayerHelper.java | 9 ------
.../newpipe/player/helper/PlayerHolder.java | 7 ++--
.../schabi/newpipe/util/NavigationHelper.java | 28 ++++++++--------
11 files changed, 58 insertions(+), 41 deletions(-)
create mode 100644 app/src/main/java/org/schabi/newpipe/player/PlayerType.java
diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
index 1194b4068..d055da1e8 100644
--- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
@@ -60,7 +60,7 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.local.dialog.PlaylistDialog;
-import org.schabi.newpipe.player.PlayerService;
+import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
@@ -630,8 +630,8 @@ public class RouterActivity extends AppCompatActivity {
}
// ...the player is not running or in normal Video-mode/type
- final PlayerService.PlayerType playerType = PlayerHolder.getInstance().getType();
- return playerType == null || playerType == PlayerService.PlayerType.MAIN;
+ final PlayerType playerType = PlayerHolder.getInstance().getType();
+ return playerType == null || playerType == PlayerType.MAIN;
}
private void openAddToPlaylistDialog() {
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 5dc6bb436..92e7e4f16 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
@@ -90,7 +90,7 @@ import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.PlayerService;
-import org.schabi.newpipe.player.PlayerService.PlayerType;
+import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.event.OnKeyDownListener;
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener;
import org.schabi.newpipe.player.helper.PlayerHelper;
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java
index aabd64744..e44048473 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java
@@ -43,7 +43,7 @@ import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.ktx.AnimationType;
import org.schabi.newpipe.local.subscription.SubscriptionManager;
import org.schabi.newpipe.local.feed.notifications.NotificationHelper;
-import org.schabi.newpipe.player.PlayerService.PlayerType;
+import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.util.ExtractorHelper;
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java
index 65fd8ada1..e3caeb522 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java
@@ -43,7 +43,7 @@ import org.schabi.newpipe.info_list.dialog.InfoItemDialog;
import org.schabi.newpipe.info_list.dialog.StreamDialogDefaultEntry;
import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
-import org.schabi.newpipe.player.PlayerService.PlayerType;
+import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
import org.schabi.newpipe.util.ExtractorHelper;
diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java
index 3bec07dcc..7fc72e064 100644
--- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java
@@ -43,7 +43,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.info_list.dialog.InfoItemDialog;
import org.schabi.newpipe.local.BaseLocalListFragment;
import org.schabi.newpipe.local.history.HistoryRecordManager;
-import org.schabi.newpipe.player.PlayerService.PlayerType;
+import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.util.Localization;
diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java
index 2d44c6449..17b5a1985 100644
--- a/app/src/main/java/org/schabi/newpipe/player/Player.java
+++ b/app/src/main/java/org/schabi/newpipe/player/Player.java
@@ -32,7 +32,6 @@ import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static org.schabi.newpipe.player.helper.PlayerHelper.isPlaybackResumeEnabled;
import static org.schabi.newpipe.player.helper.PlayerHelper.nextRepeatMode;
import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePlaybackParametersFromPrefs;
-import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePlayerTypeFromIntent;
import static org.schabi.newpipe.player.helper.PlayerHelper.retrieveSeekDurationFromPreferences;
import static org.schabi.newpipe.player.helper.PlayerHelper.savePlaybackParametersToPrefs;
import static org.schabi.newpipe.player.notification.NotificationConstants.ACTION_CLOSE;
@@ -95,7 +94,6 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.local.history.HistoryRecordManager;
-import org.schabi.newpipe.player.PlayerService.PlayerType;
import org.schabi.newpipe.player.event.PlayerEventListener;
import org.schabi.newpipe.player.event.PlayerServiceEventListener;
import org.schabi.newpipe.player.helper.AudioReactor;
@@ -308,7 +306,7 @@ public final class Player implements PlaybackListener, Listener {
}
final PlayerType oldPlayerType = playerType;
- playerType = retrievePlayerTypeFromIntent(intent);
+ playerType = PlayerType.retrieveFromIntent(intent);
initUIsForCurrentPlayerType();
// We need to setup audioOnly before super(), see "sourceOf"
isAudioOnly = audioPlayerSelected();
diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
index 14e8262d6..8d982617a 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
@@ -42,11 +42,6 @@ public final class PlayerService extends Service {
private final IBinder mBinder = new PlayerService.LocalBinder();
- public enum PlayerType {
- MAIN,
- AUDIO,
- POPUP
- }
/*//////////////////////////////////////////////////////////////////////////
// Service's LifeCycle
diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayerType.java b/app/src/main/java/org/schabi/newpipe/player/PlayerType.java
new file mode 100644
index 000000000..171a70395
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/player/PlayerType.java
@@ -0,0 +1,32 @@
+package org.schabi.newpipe.player;
+
+import static org.schabi.newpipe.player.Player.PLAYER_TYPE;
+
+import android.content.Intent;
+
+public enum PlayerType {
+ MAIN,
+ AUDIO,
+ POPUP;
+
+ /**
+ * @return an integer representing this {@link PlayerType}, to be used to save it in intents
+ * @see #retrieveFromIntent(Intent) Use retrieveFromIntent() to retrieve and convert player type
+ * integers from an intent
+ */
+ public int valueForIntent() {
+ return ordinal();
+ }
+
+ /**
+ * @param intent the intent to retrieve a player type from
+ * @return the player type integer retrieved from the intent, converted back into a {@link
+ * PlayerType}, or {@link PlayerType#MAIN} if there is no player type extra in the
+ * intent
+ * @throws ArrayIndexOutOfBoundsException if the intent contains an invalid player type integer
+ * @see #valueForIntent() Use valueForIntent() to obtain valid player type integers
+ */
+ public static PlayerType retrieveFromIntent(final Intent intent) {
+ return values()[intent.getIntExtra(PLAYER_TYPE, MAIN.valueForIntent())];
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index d1d29dd71..fb346f5ba 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -3,7 +3,6 @@ package org.schabi.newpipe.player.helper;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
-import static org.schabi.newpipe.player.Player.PLAYER_TYPE;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI;
@@ -14,7 +13,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.SuppressLint;
import android.content.Context;
-import android.content.Intent;
import android.content.SharedPreferences;
import android.provider.Settings;
import android.view.accessibility.CaptioningManager;
@@ -44,7 +42,6 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.utils.Utils;
import org.schabi.newpipe.player.Player;
-import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
@@ -428,12 +425,6 @@ public final class PlayerHelper {
// Utils used by player
////////////////////////////////////////////////////////////////////////////
- public static PlayerService.PlayerType retrievePlayerTypeFromIntent(final Intent intent) {
- // If you want to open popup from the app just include Constants.POPUP_ONLY into an extra
- return PlayerService.PlayerType.values()[
- intent.getIntExtra(PLAYER_TYPE, PlayerService.PlayerType.MAIN.ordinal())];
- }
-
public static boolean isPlaybackResumeEnabled(final Player player) {
return player.getPrefs().getBoolean(
player.getContext().getString(R.string.enable_watch_history_key), true)
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java
index cb613f854..5eaecd48d 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java
@@ -18,6 +18,7 @@ import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.Player;
+import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.event.PlayerServiceEventListener;
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener;
import org.schabi.newpipe.player.playqueue.PlayQueue;
@@ -46,13 +47,13 @@ public final class PlayerHolder {
@Nullable private Player player;
/**
- * Returns the current {@link PlayerService.PlayerType} of the {@link PlayerService} service,
- * otherwise `null` if no service running.
+ * Returns the current {@link PlayerType} of the {@link PlayerService} service,
+ * otherwise `null` if no service is running.
*
* @return Current PlayerType
*/
@Nullable
- public PlayerService.PlayerType getType() {
+ public PlayerType getType() {
if (player == null) {
return null;
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index 36b2bd46d..3b2c52691 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -51,9 +51,9 @@ import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
import org.schabi.newpipe.player.PlayerService;
-import org.schabi.newpipe.player.PlayerService.PlayerType;
import org.schabi.newpipe.player.PlayQueueActivity;
import org.schabi.newpipe.player.Player;
+import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue;
@@ -91,7 +91,7 @@ public final class NavigationHelper {
intent.putExtra(Player.PLAY_QUEUE_KEY, cacheKey);
}
}
- intent.putExtra(Player.PLAYER_TYPE, PlayerService.PlayerType.MAIN.ordinal());
+ intent.putExtra(Player.PLAYER_TYPE, PlayerType.MAIN.valueForIntent());
intent.putExtra(Player.RESUME_PLAYBACK, resumePlayback);
return intent;
@@ -164,7 +164,7 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerIntent(context, PlayerService.class, queue, resumePlayback);
- intent.putExtra(Player.PLAYER_TYPE, PlayerService.PlayerType.POPUP.ordinal());
+ intent.putExtra(Player.PLAYER_TYPE, PlayerType.POPUP.valueForIntent());
ContextCompat.startForegroundService(context, intent);
}
@@ -175,7 +175,7 @@ public final class NavigationHelper {
.show();
final Intent intent = getPlayerIntent(context, PlayerService.class, queue, resumePlayback);
- intent.putExtra(Player.PLAYER_TYPE, PlayerService.PlayerType.AUDIO.ordinal());
+ intent.putExtra(Player.PLAYER_TYPE, PlayerType.AUDIO.valueForIntent());
ContextCompat.startForegroundService(context, intent);
}
@@ -186,15 +186,15 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerEnqueueIntent(context, PlayerService.class, queue);
- intent.putExtra(Player.PLAYER_TYPE, playerType.ordinal());
+ intent.putExtra(Player.PLAYER_TYPE, playerType.valueForIntent());
ContextCompat.startForegroundService(context, intent);
}
public static void enqueueOnPlayer(final Context context, final PlayQueue queue) {
PlayerType playerType = PlayerHolder.getInstance().getType();
- if (!PlayerHolder.getInstance().isPlayerOpen()) {
+ if (playerType == null) {
Log.e(TAG, "Enqueueing but no player is open; defaulting to background player");
- playerType = PlayerService.PlayerType.AUDIO;
+ playerType = PlayerType.AUDIO;
}
enqueueOnPlayer(context, queue, playerType);
@@ -203,14 +203,14 @@ public final class NavigationHelper {
/* ENQUEUE NEXT */
public static void enqueueNextOnPlayer(final Context context, final PlayQueue queue) {
PlayerType playerType = PlayerHolder.getInstance().getType();
- if (!PlayerHolder.getInstance().isPlayerOpen()) {
+ if (playerType == null) {
Log.e(TAG, "Enqueueing next but no player is open; defaulting to background player");
- playerType = PlayerService.PlayerType.AUDIO;
+ playerType = PlayerType.AUDIO;
}
Toast.makeText(context, R.string.enqueued_next, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerEnqueueNextIntent(context, PlayerService.class, queue);
- intent.putExtra(Player.PLAYER_TYPE, playerType.ordinal());
+ intent.putExtra(Player.PLAYER_TYPE, playerType.valueForIntent());
ContextCompat.startForegroundService(context, intent);
}
@@ -414,14 +414,14 @@ public final class NavigationHelper {
final boolean switchingPlayers) {
final boolean autoPlay;
- @Nullable final PlayerService.PlayerType playerType = PlayerHolder.getInstance().getType();
- if (!PlayerHolder.getInstance().isPlayerOpen()) {
+ @Nullable final PlayerType playerType = PlayerHolder.getInstance().getType();
+ if (playerType == null) {
// no player open
autoPlay = PlayerHelper.isAutoplayAllowedByUser(context);
} else if (switchingPlayers) {
// switching player to main player
autoPlay = PlayerHolder.getInstance().isPlaying(); // keep play/pause state
- } else if (playerType == PlayerService.PlayerType.MAIN) {
+ } else if (playerType == PlayerType.MAIN) {
// opening new stream while already playing in main player
autoPlay = PlayerHelper.isAutoplayAllowedByUser(context);
} else {
@@ -436,7 +436,7 @@ public final class NavigationHelper {
// Situation when user switches from players to main player. All needed data is
// here, we can start watching (assuming newQueue equals playQueue).
// Starting directly in fullscreen if the previous player type was popup.
- detailFragment.openVideoPlayer(playerType == PlayerService.PlayerType.POPUP
+ detailFragment.openVideoPlayer(playerType == PlayerType.POPUP
|| PlayerHelper.isStartMainPlayerFullscreenEnabled(context));
} else {
detailFragment.selectAndLoadVideo(serviceId, url, title, playQueue);
From 4536e8b55b59502471cd0b409f8b68e8cff600d2 Mon Sep 17 00:00:00 2001
From: TacoTheDank
Date: Thu, 14 Jul 2022 01:48:52 -0400
Subject: [PATCH 046/152] Update some miscellaneous libraries
---
app/build.gradle | 18 +++++++++---------
build.gradle | 2 +-
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 9867037e6..787dd7833 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -95,7 +95,7 @@ android {
}
ext {
- checkstyleVersion = '10.0'
+ checkstyleVersion = '10.3.1'
androidxLifecycleVersion = '2.3.1'
androidxRoomVersion = '2.4.2'
@@ -110,7 +110,7 @@ ext {
leakCanaryVersion = '2.5'
stethoVersion = '1.6.0'
mockitoVersion = '4.0.0'
- assertJVersion = '3.22.0'
+ assertJVersion = '3.23.1'
}
configurations {
@@ -179,7 +179,7 @@ sonarqube {
dependencies {
/** Desugaring **/
- coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
+ coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
/** NewPipe libraries **/
// You can use a local version by uncommenting a few lines in settings.gradle
@@ -191,7 +191,7 @@ dependencies {
/** Checkstyle **/
checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}"
- ktlint 'com.pinterest:ktlint:0.44.0'
+ ktlint 'com.pinterest:ktlint:0.45.2'
/** Kotlin **/
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlin_version}"
@@ -199,14 +199,14 @@ dependencies {
/** AndroidX **/
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.cardview:cardview:1.0.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
- implementation 'androidx.core:core-ktx:1.6.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'androidx.fragment:fragment-ktx:1.3.6'
implementation "androidx.lifecycle:lifecycle-livedata:${androidxLifecycleVersion}"
implementation "androidx.lifecycle:lifecycle-viewmodel:${androidxLifecycleVersion}"
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
- implementation 'androidx.media:media:1.5.0'
+ implementation 'androidx.media:media:1.6.0'
implementation 'androidx.preference:preference:1.2.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "androidx.room:room-runtime:${androidxRoomVersion}"
@@ -226,7 +226,7 @@ dependencies {
kapt "frankiesardo:icepick-processor:${icepickVersion}"
// HTML parser
- implementation "org.jsoup:jsoup:1.14.3"
+ implementation "org.jsoup:jsoup:1.15.2"
// HTTP client
//noinspection GradleDependency --> do not update okhttp to keep supporting Android 4.4 users
@@ -274,7 +274,7 @@ dependencies {
implementation "com.jakewharton.rxbinding4:rxbinding:4.0.0"
// Date and time formatting
- implementation "org.ocpsoft.prettytime:prettytime:5.0.2.Final"
+ implementation "org.ocpsoft.prettytime:prettytime:5.0.3.Final"
/** Debugging **/
// Memory leak detection
diff --git a/build.gradle b/build.gradle
index bea444fab..322a47a6f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,7 +7,7 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.2.0'
+ classpath 'com.android.tools.build:gradle:7.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
From c1e78cf55bf6e4178ac3ef3b4f7bae52c7f992c0 Mon Sep 17 00:00:00 2001
From: TacoTheDank
Date: Thu, 14 Jul 2022 03:23:45 -0400
Subject: [PATCH 047/152] Update OkHttp to 4.x
---
app/build.gradle | 3 +--
app/src/main/java/org/schabi/newpipe/DownloaderImpl.java | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 9867037e6..b5e26e8fc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -229,8 +229,7 @@ dependencies {
implementation "org.jsoup:jsoup:1.14.3"
// HTTP client
- //noinspection GradleDependency --> do not update okhttp to keep supporting Android 4.4 users
- implementation "com.squareup.okhttp3:okhttp:3.12.13"
+ implementation "com.squareup.okhttp3:okhttp:4.10.0"
// Media player
implementation "com.google.android.exoplayer:exoplayer-core:${exoPlayerVersion}"
diff --git a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java
index f2803dc2f..79d2ad7b7 100644
--- a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java
@@ -135,7 +135,7 @@ public final class DownloaderImpl extends Downloader {
RequestBody requestBody = null;
if (dataToSend != null) {
- requestBody = RequestBody.create(null, dataToSend);
+ requestBody = RequestBody.create(dataToSend);
}
final okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder()
From cc7a8fb1a611299bab6b574b75b602b38a23b2d9 Mon Sep 17 00:00:00 2001
From: krlvm <51774833+krlvm@users.noreply.github.com>
Date: Tue, 21 Jun 2022 20:22:39 +0300
Subject: [PATCH 048/152] Improve image placeholders
- Show placeholders until the image is loaded because timeout can be very long and missing profile pictures and video thumbnails make app inconvenient to use
- Adapt profile picture and video thumbnail placeholders to light theme
- Replace profile picture and video thumbnail placeholders with vector graphics
---
.../fragments/detail/VideoDetailFragment.java | 4 +-
.../schabi/newpipe/util/PicassoHelper.java | 17 +++-
app/src/main/res/drawable-nodpi/buddy.png | Bin 1168 -> 0 bytes
.../res/drawable-nodpi/buddy_channel_item.png | Bin 1051 -> 0 bytes
.../res/drawable-nodpi/dummy_thumbnail.png | Bin 956 -> 0 bytes
.../drawable-nodpi/dummy_thumbnail_dark.png | Bin 105 -> 134 bytes
.../dummy_thumbnail_playlist.png | Bin 1225 -> 0 bytes
app/src/main/res/drawable/buddy.xml | 31 ++++++++
app/src/main/res/drawable/dummy_thumbnail.xml | 22 ++++++
.../res/drawable/dummy_thumbnail_playlist.xml | 30 +++++++
.../res/layout/list_channel_grid_item.xml | 2 +-
.../res/layout/list_channel_mini_item.xml | 2 +-
.../res/layout/list_comments_mini_item.xml | 2 +-
.../res/layout/picker_subscription_item.xml | 2 +-
app/src/main/res/values-night/colors.xml | 3 +
app/src/main/res/values/colors.xml | 3 +
assets/buddy_channel_item.svg | 73 ------------------
assets/dummy_thumbnail.svg | 7 ++
assets/dummy_thumbnail_playlist.svg | 8 ++
19 files changed, 125 insertions(+), 81 deletions(-)
delete mode 100644 app/src/main/res/drawable-nodpi/buddy.png
delete mode 100644 app/src/main/res/drawable-nodpi/buddy_channel_item.png
delete mode 100644 app/src/main/res/drawable-nodpi/dummy_thumbnail.png
delete mode 100644 app/src/main/res/drawable-nodpi/dummy_thumbnail_playlist.png
create mode 100644 app/src/main/res/drawable/buddy.xml
create mode 100644 app/src/main/res/drawable/dummy_thumbnail.xml
create mode 100644 app/src/main/res/drawable/dummy_thumbnail_playlist.xml
delete mode 100644 assets/buddy_channel_item.svg
create mode 100644 assets/dummy_thumbnail.svg
create mode 100644 assets/dummy_thumbnail_playlist.svg
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 278d472d4..78f3772e9 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
@@ -714,7 +714,7 @@ public final class VideoDetailFragment
}
private void initThumbnailViews(@NonNull final StreamInfo info) {
- PicassoHelper.loadThumbnail(info.getThumbnailUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
+ PicassoHelper.loadDetailsThumbnail(info.getThumbnailUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
.into(binding.detailThumbnailImageView, new Callback() {
@Override
public void onSuccess() {
@@ -2361,7 +2361,7 @@ public final class VideoDetailFragment
binding.overlayTitleTextView.setText(isEmpty(overlayTitle) ? "" : overlayTitle);
binding.overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader);
binding.overlayThumbnail.setImageResource(R.drawable.dummy_thumbnail_dark);
- PicassoHelper.loadThumbnail(thumbnailUrl).tag(PICASSO_VIDEO_DETAILS_TAG)
+ PicassoHelper.loadDetailsThumbnail(thumbnailUrl).tag(PICASSO_VIDEO_DETAILS_TAG)
.into(binding.overlayThumbnail);
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/PicassoHelper.java b/app/src/main/java/org/schabi/newpipe/util/PicassoHelper.java
index aabc459d0..223e8ac9c 100644
--- a/app/src/main/java/org/schabi/newpipe/util/PicassoHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/PicassoHelper.java
@@ -104,6 +104,10 @@ public final class PicassoHelper {
return loadImageDefault(url, R.drawable.dummy_thumbnail);
}
+ public static RequestCreator loadDetailsThumbnail(final String url) {
+ return loadImageDefault(url, R.drawable.dummy_thumbnail, false);
+ }
+
public static RequestCreator loadBanner(final String url) {
return loadImageDefault(url, R.drawable.channel_banner);
}
@@ -189,15 +193,24 @@ public final class PicassoHelper {
private static RequestCreator loadImageDefault(final String url, final int placeholderResId) {
+ return loadImageDefault(url, placeholderResId, true);
+ }
+
+ private static RequestCreator loadImageDefault(final String url, final int placeholderResId,
+ final boolean showPlaceholderWhileLoading) {
if (!shouldLoadImages || isBlank(url)) {
return picassoInstance
.load((String) null)
.placeholder(placeholderResId) // show placeholder when no image should load
.error(placeholderResId);
} else {
- return picassoInstance
+ final RequestCreator requestCreator = picassoInstance
.load(url)
- .error(placeholderResId); // don't show placeholder while loading, only on error
+ .error(placeholderResId);
+ if (showPlaceholderWhileLoading) {
+ requestCreator.placeholder(placeholderResId);
+ }
+ return requestCreator;
}
}
}
diff --git a/app/src/main/res/drawable-nodpi/buddy.png b/app/src/main/res/drawable-nodpi/buddy.png
deleted file mode 100644
index 8713ee02bfa8cd492bf79ed4730ca4060ceeb631..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 1168
zcmV;B1aJF^P)b~j1!&(iVkGA*yRLsUHxctK)V
zbrwUKLgK~AqOlZmKgKJ|YYQQFIo?ozuk3;}eY~-(u?X@o$J-OLt0fRsC3shIYX#(-
zNuCL1%5yBL~_YZH(P`V$pD
zqy|Nz=7uyeXe13Uq?I5_ww#bl3bN7*A4KIKEK_Wd1xQxb3@jDYkVb%~h8CjwU@E7D)L^S7h2&r>r-a;rv3o+u0E`Xk
zAPrb+$RGt+E2toy1Zz?eLH1y7PXrl(xiJmoD!`n$l0ZtZSCT*`U~fzTQ3=?K6#?V~
z12qJY9SpP~fJ|VZ2?3-B1NHPn6pYkqhqN%#Njs#1k@nglYZz&x9WsTHrrIF`7-^^-
z(ua{U?T{2kO0`2Ij3l)~1dJ5>0ucdX86@`ppFO<%W-wA;J7j3tN0jiPaRVc*wL|tW
z(m^}q2qU%LA3lWRpvN%`H1XxgbV~qfVW4BUR(0a6bI$P>d_(L(AznCe$_5LNcT*v+jXfvEir
znCq2FKcw!%K>b=XJ&yxYb}t60>+zM-w&x0SWt3!Cq&I*
zNwe-fkfsM~>K)$>DFtk5^F~NFgJn&-w?NJrtSh^`9@3_;u;ln!NFBq<;`()vQozzg
z`5MShz}m$2<&X`mZuwHk3YNEi8DtCV+q?vFD`0)1d>(Ru3yJzU$T5Z!#m&=@OA1Fy
zFHb?b49=9RCm;nJYW{yn1*fY12RX-Zs`&IDNDjx!)juH{IM?Q1kXFFCMEf^H4d7q{
z^%vw8PPYFO(j{=RwEF|Hgrlu~hg@SgT73NtGKaG*euZ2GoK0MRfvn(g>z|NL!r^51
z1G0nDl|LYTI9>J~a)jfx-ym~1-r_4nC2+jtE94%|*L;C2;C#z3kRF_`_Zf1A2VFiv
zDtJ)!2~xm==AR%p@Sy%`|M
z$uorG8CUd71_tH>o-U3d6}R4;Zxmo);9%JJhx3$K|NgTH#ezx%!PgEjI8j$!K5O|Z
zzLvy2;(yc}-&{ENO`)%0bIaX(=gaM!R6~nC-9PwPV)Ci;kG~avnkTi?=a=2jTl4N{
zx83>Fc`SZLVO{lFf$g#n=dZlDu5RW8EBOcZD);-Ra}@48_}^gXWceW8kKC7nDm?av
z{7}t$snUMO=#NqLMCqU`n}bt=oWDu=2UgEil(xxLHhi++!=AZ&CIl^H4fW#QnYATp
z-6p3wuHM%=xgr;BUAkm~*Fw`!POgnF5?&l>dGbPKx=@gGNm7=gqISuY(;O>>OQu)|
zDq5Fp6BaabN>AogG;e*E$K+Hb5W&qcv*ExL`y-M927R_qIE2){P2ly&x#?`@_^8`9
zg-Iy*n*g`aG+Pzc&MCG>8e9&^Epl)=I^oA9p|5Gv|9_O;FYs6>^>zA1iRm9dwuc(C
zHD=zanXpxM$-BblK7*9o({(RbU6}0qM(zE{jZVSpOW18czUVz*{WmegW?q`K#E&;8
zIozMM@LrYpw@^xI>NEM`BpI9A=8v3S9eR{`I96BZiOuzlqdMoBoK|%@RYxi+A9<^5
zwW<2Je9uCyzi!yp4gH%GgXh|nsmIJ$}Rs%;$ZVd<&qPs
zt>P~&b376sblSD>L>`vk$|pWayFmy*8bpJ
zDRAea_X(MUx-~5p%@2A$3j{SdK2%I$V>9Mg0=K=XbS{$IP4O
z{n?Q9EWx0EHvgt=%|hblFXA#zo8%>#r^fe*&f;-Q{rKYTc1xbzcb$J8XBILuTkltv
z5oR&^XcH35FX-~?gUqFvqkWdPs{=l)e{oXdf!djZXKw!r)ap6^?$Eit+B>((C@Ahr
z%8CD%wr7ifRPy0|&a>oA>)UI$``IM7zB>BV)^x8?{0f`8h6Y=%9gnIuywI@r*jZu|
znvoyGwTrDTQesQewD3gn@o>{EqW2>-&>r*LXZ_(Z|zYQa)$A*kiinPNr$lkNR(`
zm;6sR%zC#cI!)?-n#K9myA;1)`|)ty({I&=+su4<5++@__3=@4bX@G?s;5ox
STg?c}*bJVoelF{r5}E*aKG6LD
diff --git a/app/src/main/res/drawable-nodpi/dummy_thumbnail.png b/app/src/main/res/drawable-nodpi/dummy_thumbnail.png
deleted file mode 100644
index 86f454186e1f39cf9ca3ac28dd95502fdbce4655..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 956
zcmeAS@N?(olHy`uVBq!ia0y~yU|a=cf8YQT3?*{6LDa*vT`5;~7`oJ0;^v
zbkO&@i;A40S_@}sggCW&t!Uwz8UW%7X@xkchOB7uS`olGH2}z62;_nkpmA}jU-kOz
z?QT77ynJ~dP~_Fwoytz3TYq1XT)67y-s}+O@=*J%Z%?i;Mux_3
zttx%jux8czTeWX`0zzf=t(8Met1B)GE?gC5W4~Bx?de}%la}pR;k0Z=9mDFTWjn$`
zFNj=Ub!z6LsL;URn2^Ojg@LhG){9#l-MR`adqqS%^n}QD{)96?Wl{-U-LH!OR=otO
zRE(Y`e_)B`y3nto-Qsg60IAvE!BqKrE0CQfuM(X^i>I|_E!nISGXK@})Aa@JqL$g8
zm}h)>kQeHDc2>Ysn;nZ+MeTdl5Wos#o!Z^fmi4Rp@(R0a^3&@*dbEBXlnuRl__lyn
z$kvL&a|?hT{wv|os`YerO&ch7mWLgHnG*aK9*E?oBd!%lXN&;yEws~T?4U2%!8
zGZ1W|y^5RZ-?x4t?_ckKX>j0(Z0M6x$B_N^avJup4{*IV!SU;B-T3be3%P7WzHRvT
zT2`;>NC4{}%cpy^(mWcq62G*+x*om%eZ6_e{GzzjHa))zrV$y6Uoi3%n%#7VP>pe=l=;*57T*`9qKWzO`aqa+~mqO>CQ2
z)THPwm^~vpdBvu@-i2HhD|K63m`>kT3RDwn0E0NDPwL>%ybA~*haoIVPItuU|?H)Z&(<0e9y%;t!Ks7D}w%g6j_y9
zd%x&~zu$seOMqsVMa~vk_4YR(N9eKgi2-l3#XkMwT{Y!;egH2oIOXC?*T@N(n0)X>
Ym3dv9k!XF~Gf=klboFyt=akR{0K-zPssI20
diff --git a/app/src/main/res/drawable-nodpi/dummy_thumbnail_dark.png b/app/src/main/res/drawable-nodpi/dummy_thumbnail_dark.png
index 02f698918fff753ac9d5bfe6091ac8349435243b..0e73416edeb6371b992c6c150b42d46a1c22f156 100644
GIT binary patch
literal 134
zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k92}K#X;^)4C~IxyaaMs(j9#r85lP9
zbN@+X1@buyJR*yMny-N{YhX3vTXZ8bmyq+$OArj%q2?+^5_!$^k
V7#Ru_Qn`T=44$rjF6*2UngBC(9*6({
literal 105
zcmeAS@N?(olHy`uVBq!ia0vp^?m(=;2qYLEakt!I&(;+6**`aRLM5QNh-iK2A&*Qo$V9E1zaSW-r_2yzD4^RoyhCjTU&MyAT<3;rZUGZhj37hA-&Z3Ve?Q;Lp*yG@)pezZZRsB|P*hnYQrnlAje`Hk3S|LIAbp7KR{)xjUW9eGv}CnXjKosifj&vP{)
z{F(dzylTf|5>uUyZFrlof^F{pzEkUxCV%AMNDSI2zNq~zhh%cdvoxM%iL(y|@LKVM
zj8;tU@ls6AYRP4AHcj8~jpa7OykiS~Yq
zIX!PnLS(|NYz7z!bj^~
zZ=+f1Q{rrYJ0Hu6Q=7bT>b}GJ{6=YkH`g|%JekfenO*pyt7mzUT|+Nz(U+W(+CO@x_M8ooTwdrYDaq@nHhE&a9MCF8Dyo_L9U1(RTviPS^Ur$ZX;p6|W
zncGadSpV0}?OJ}ynuom&F)JPwd-F;Dy`G0IbQBJ(j>R>r@XP{JfC-?%^>7C`(3r<)-(T2l)gh!>>E3+i$JRmUbd(d
z&UHSqL)-N>gOT2n`cUKPZ@Ls7e+b?3S0Q<$p6hKEBfb6QnRhuZ9yV*~X%@c-B)fw^
zl8=Knyfu5660>x{f0bKp6AJ4Da_vvtun-5DwxZ_gUcb8=?kYU4`lJSw`}nit+wpHN
v9Drp2gTsXVUlpc1f%7!MjLuFbP0l+XkK#Ah!m
diff --git a/app/src/main/res/drawable/buddy.xml b/app/src/main/res/drawable/buddy.xml
new file mode 100644
index 000000000..b7d23c4b1
--- /dev/null
+++ b/app/src/main/res/drawable/buddy.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/dummy_thumbnail.xml b/app/src/main/res/drawable/dummy_thumbnail.xml
new file mode 100644
index 000000000..5114fda32
--- /dev/null
+++ b/app/src/main/res/drawable/dummy_thumbnail.xml
@@ -0,0 +1,22 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/dummy_thumbnail_playlist.xml b/app/src/main/res/drawable/dummy_thumbnail_playlist.xml
new file mode 100644
index 000000000..683b814c9
--- /dev/null
+++ b/app/src/main/res/drawable/dummy_thumbnail_playlist.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_channel_grid_item.xml b/app/src/main/res/layout/list_channel_grid_item.xml
index d9084bbe9..9f92c35a7 100644
--- a/app/src/main/res/layout/list_channel_grid_item.xml
+++ b/app/src/main/res/layout/list_channel_grid_item.xml
@@ -18,7 +18,7 @@
android:layout_centerHorizontal="true"
android:layout_margin="2dp"
android:contentDescription="@string/detail_uploader_thumbnail_view_description"
- android:src="@drawable/buddy_channel_item"
+ android:src="@drawable/buddy"
app:shapeAppearance="@style/CircularImageView"
tools:ignore="RtlHardcoded" />
diff --git a/app/src/main/res/layout/list_channel_mini_item.xml b/app/src/main/res/layout/list_channel_mini_item.xml
index b66e07a12..e03f7c2fa 100644
--- a/app/src/main/res/layout/list_channel_mini_item.xml
+++ b/app/src/main/res/layout/list_channel_mini_item.xml
@@ -17,7 +17,7 @@
android:layout_centerVertical="true"
android:layout_marginStart="3dp"
android:layout_marginRight="15dp"
- android:src="@drawable/buddy_channel_item"
+ android:src="@drawable/buddy"
app:shapeAppearance="@style/CircularImageView"
tools:ignore="RtlHardcoded" />
diff --git a/app/src/main/res/layout/list_comments_mini_item.xml b/app/src/main/res/layout/list_comments_mini_item.xml
index 6bd363311..ba984e0ff 100644
--- a/app/src/main/res/layout/list_comments_mini_item.xml
+++ b/app/src/main/res/layout/list_comments_mini_item.xml
@@ -17,7 +17,7 @@
android:layout_centerVertical="true"
android:layout_marginStart="3dp"
android:layout_marginRight="15dp"
- android:src="@drawable/buddy_channel_item"
+ android:src="@drawable/buddy"
app:shapeAppearance="@style/CircularImageView"
tools:ignore="RtlHardcoded" />
diff --git a/app/src/main/res/layout/picker_subscription_item.xml b/app/src/main/res/layout/picker_subscription_item.xml
index c858ccc4e..f6e5f3587 100644
--- a/app/src/main/res/layout/picker_subscription_item.xml
+++ b/app/src/main/res/layout/picker_subscription_item.xml
@@ -22,7 +22,7 @@
android:layout_width="48dp"
android:layout_height="48dp"
app:shapeAppearance="@style/CircularImageView"
- tools:src="@drawable/buddy_channel_item" />
+ tools:src="@drawable/buddy" />
@color/white
@color/white
+
+ #6C6C6C
+ #999999