Merge pull request #5371 from Stypox/merge-player

Merge player classes into a single one
This commit is contained in:
Robin 2021-01-14 10:43:11 +01:00 committed by GitHub
commit c90696e67e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 4571 additions and 5267 deletions

View file

@ -53,7 +53,7 @@
</service> </service>
<activity <activity
android:name=".player.BackgroundPlayerActivity" android:name=".player.PlayQueueActivity"
android:label="@string/title_activity_play_queue" android:label="@string/title_activity_play_queue"
android:launchMode="singleTask" /> android:launchMode="singleTask" />

View file

@ -70,7 +70,7 @@ import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.MainFragment; import org.schabi.newpipe.fragments.MainFragment;
import org.schabi.newpipe.fragments.detail.VideoDetailFragment; import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
import org.schabi.newpipe.fragments.list.search.SearchFragment; import org.schabi.newpipe.fragments.list.search.SearchFragment;
import org.schabi.newpipe.player.VideoPlayer; import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.event.OnKeyDownListener; import org.schabi.newpipe.player.event.OnKeyDownListener;
import org.schabi.newpipe.player.helper.PlayerHolder; import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
@ -759,7 +759,7 @@ public class MainActivity extends AppCompatActivity {
switch (linkType) { switch (linkType) {
case STREAM: case STREAM:
final String intentCacheKey = intent.getStringExtra( final String intentCacheKey = intent.getStringExtra(
VideoPlayer.PLAY_QUEUE_KEY); Player.PLAY_QUEUE_KEY);
final PlayQueue playQueue = intentCacheKey != null final PlayQueue playQueue = intentCacheKey != null
? SerializedCache.getInstance() ? SerializedCache.getInstance()
.take(intentCacheKey, PlayQueue.class) .take(intentCacheKey, PlayQueue.class)

View file

@ -49,7 +49,6 @@ import androidx.viewpager.widget.ViewPager;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayout;
@ -80,9 +79,8 @@ import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment;
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.local.dialog.PlaylistCreationDialog; import org.schabi.newpipe.local.dialog.PlaylistCreationDialog;
import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.player.BasePlayer; import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.MainPlayer; import org.schabi.newpipe.player.MainPlayer;
import org.schabi.newpipe.player.VideoPlayerImpl;
import org.schabi.newpipe.player.event.OnKeyDownListener; import org.schabi.newpipe.player.event.OnKeyDownListener;
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener; import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
@ -255,14 +253,14 @@ public final class VideoDetailFragment
private ContentObserver settingsContentObserver; private ContentObserver settingsContentObserver;
private MainPlayer playerService; private MainPlayer playerService;
private VideoPlayerImpl player; private Player player;
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Service management // Service management
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override @Override
public void onServiceConnected(final VideoPlayerImpl connectedPlayer, public void onServiceConnected(final Player connectedPlayer,
final MainPlayer connectedPlayerService, final MainPlayer connectedPlayerService,
final boolean playAfterConnect) { final boolean playAfterConnect) {
player = connectedPlayer; player = connectedPlayer;
@ -539,7 +537,7 @@ public final class VideoDetailFragment
break; break;
case R.id.overlay_play_pause_button: case R.id.overlay_play_pause_button:
if (playerIsNotStopped()) { if (playerIsNotStopped()) {
player.onPlayPause(); player.playPause();
player.hideControls(0, 0); player.hideControls(0, 0);
showSystemUi(); showSystemUi();
} else { } else {
@ -805,7 +803,7 @@ public final class VideoDetailFragment
// If we are in fullscreen mode just exit from it via first back press // If we are in fullscreen mode just exit from it via first back press
if (player != null && player.isFullscreen()) { if (player != null && player.isFullscreen()) {
if (!DeviceUtils.isTablet(activity)) { if (!DeviceUtils.isTablet(activity)) {
player.onPause(); player.pause();
} }
restoreDefaultOrientation(); restoreDefaultOrientation();
setAutoPlay(false); setAutoPlay(false);
@ -850,7 +848,7 @@ public final class VideoDetailFragment
final PlayQueueItem playQueueItem = item.getPlayQueue().getItem(); final PlayQueueItem playQueueItem = item.getPlayQueue().getItem();
// Update title, url, uploader from the last item in the stack (it's current now) // Update title, url, uploader from the last item in the stack (it's current now)
final boolean isPlayerStopped = player == null || player.isPlayerStopped(); final boolean isPlayerStopped = player == null || player.isStopped();
if (playQueueItem != null && isPlayerStopped) { if (playQueueItem != null && isPlayerStopped) {
updateOverlayData(playQueueItem.getTitle(), updateOverlayData(playQueueItem.getTitle(),
playQueueItem.getUploader(), playQueueItem.getThumbnailUrl()); playQueueItem.getUploader(), playQueueItem.getThumbnailUrl());
@ -1569,7 +1567,7 @@ public final class VideoDetailFragment
showMetaInfoInTextView(info.getMetaInfo(), detailMetaInfoTextView, detailMetaInfoSeparator); showMetaInfoInTextView(info.getMetaInfo(), detailMetaInfoTextView, detailMetaInfoSeparator);
if (player == null || player.isPlayerStopped()) { if (player == null || player.isStopped()) {
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl()); updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
} }
@ -1797,7 +1795,7 @@ public final class VideoDetailFragment
setOverlayPlayPauseImage(player != null && player.isPlaying()); setOverlayPlayPauseImage(player != null && player.isPlaying());
switch (state) { switch (state) {
case BasePlayer.STATE_PLAYING: case Player.STATE_PLAYING:
if (positionView.getAlpha() != 1.0f if (positionView.getAlpha() != 1.0f
&& player.getPlayQueue() != null && player.getPlayQueue() != null
&& player.getPlayQueue().getItem() != null && player.getPlayQueue().getItem() != null
@ -1814,7 +1812,7 @@ public final class VideoDetailFragment
final int duration, final int duration,
final int bufferPercent) { final int bufferPercent) {
// Progress updates every second even if media is paused. It's useless until playing // Progress updates every second even if media is paused. It's useless until playing
if (!player.getPlayer().isPlaying() || playQueue == null) { if (!player.isPlaying() || playQueue == null) {
return; return;
} }
@ -1891,10 +1889,8 @@ public final class VideoDetailFragment
if (fullscreen) { if (fullscreen) {
hideSystemUiIfNeeded(); hideSystemUiIfNeeded();
viewPager.setVisibility(View.GONE);
} else { } else {
showSystemUi(); showSystemUi();
viewPager.setVisibility(View.VISIBLE);
} }
if (relatedStreamsLayout != null) { if (relatedStreamsLayout != null) {
@ -2020,9 +2016,7 @@ public final class VideoDetailFragment
} }
private boolean playerIsNotStopped() { private boolean playerIsNotStopped() {
return player != null return player != null && !player.isStopped();
&& player.getPlayer() != null
&& player.getPlayer().getPlaybackState() != Player.STATE_IDLE;
} }
private void restoreDefaultBrightness() { private void restoreDefaultBrightness() {
@ -2073,7 +2067,7 @@ public final class VideoDetailFragment
player.checkLandscape(); player.checkLandscape();
// Let's give a user time to look at video information page if video is not playing // Let's give a user time to look at video information page if video is not playing
if (globalScreenOrientationLocked(activity) && !player.isPlaying()) { if (globalScreenOrientationLocked(activity) && !player.isPlaying()) {
player.onPlay(); player.play();
} }
} }
@ -2287,7 +2281,7 @@ public final class VideoDetailFragment
// Re-enable clicks // Re-enable clicks
setOverlayElementsClickable(true); setOverlayElementsClickable(true);
if (player != null) { if (player != null) {
player.onQueueClosed(); player.closeQueue();
} }
setOverlayLook(appBarLayout, behavior, 0); setOverlayLook(appBarLayout, behavior, 0);
break; break;

View file

@ -1,57 +0,0 @@
package org.schabi.newpipe.player;
import android.content.Intent;
import android.view.Menu;
import org.schabi.newpipe.R;
public final class BackgroundPlayerActivity extends ServicePlayerActivity {
private static final String TAG = "BackgroundPlayerActivity";
@Override
public String getTag() {
return TAG;
}
@Override
public String getSupportActionTitle() {
return getResources().getString(R.string.title_activity_play_queue);
}
@Override
public Intent getBindIntent() {
return new Intent(this, MainPlayer.class);
}
@Override
public void startPlayerListener() {
if (player instanceof VideoPlayerImpl) {
((VideoPlayerImpl) player).setActivityListener(this);
}
}
@Override
public void stopPlayerListener() {
if (player instanceof VideoPlayerImpl) {
((VideoPlayerImpl) player).removeActivityListener(this);
}
}
@Override
public int getPlayerOptionMenuResource() {
return R.menu.menu_play_queue_bg;
}
@Override
public void setupMenu(final Menu menu) {
if (player == null) {
return;
}
menu.findItem(R.id.action_switch_popup)
.setVisible(!((VideoPlayerImpl) player).popupPlayerSelected());
menu.findItem(R.id.action_switch_background)
.setVisible(!((VideoPlayerImpl) player).audioPlayerSelected());
}
}

File diff suppressed because it is too large Load diff

View file

@ -48,9 +48,9 @@ import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
*/ */
public final class MainPlayer extends Service { public final class MainPlayer extends Service {
private static final String TAG = "MainPlayer"; private static final String TAG = "MainPlayer";
private static final boolean DEBUG = BasePlayer.DEBUG; private static final boolean DEBUG = Player.DEBUG;
private VideoPlayerImpl playerImpl; private Player player;
private WindowManager windowManager; private WindowManager windowManager;
private final IBinder mBinder = new MainPlayer.LocalBinder(); private final IBinder mBinder = new MainPlayer.LocalBinder();
@ -69,8 +69,6 @@ public final class MainPlayer extends Service {
= App.PACKAGE_NAME + ".player.MainPlayer.CLOSE"; = App.PACKAGE_NAME + ".player.MainPlayer.CLOSE";
static final String ACTION_PLAY_PAUSE static final String ACTION_PLAY_PAUSE
= App.PACKAGE_NAME + ".player.MainPlayer.PLAY_PAUSE"; = App.PACKAGE_NAME + ".player.MainPlayer.PLAY_PAUSE";
static final String ACTION_OPEN_CONTROLS
= App.PACKAGE_NAME + ".player.MainPlayer.OPEN_CONTROLS";
static final String ACTION_REPEAT static final String ACTION_REPEAT
= App.PACKAGE_NAME + ".player.MainPlayer.REPEAT"; = App.PACKAGE_NAME + ".player.MainPlayer.REPEAT";
static final String ACTION_PLAY_NEXT static final String ACTION_PLAY_NEXT
@ -105,11 +103,10 @@ public final class MainPlayer extends Service {
private void createView() { private void createView() {
final PlayerBinding binding = PlayerBinding.inflate(LayoutInflater.from(this)); final PlayerBinding binding = PlayerBinding.inflate(LayoutInflater.from(this));
playerImpl = new VideoPlayerImpl(this); player = new Player(this);
playerImpl.setup(binding); player.setupFromView(binding);
playerImpl.shouldUpdateOnProgress = true;
NotificationUtil.getInstance().createNotificationAndStartForeground(playerImpl, this); NotificationUtil.getInstance().createNotificationAndStartForeground(player, this);
} }
@Override @Override
@ -119,19 +116,19 @@ public final class MainPlayer extends Service {
+ "], flags = [" + flags + "], startId = [" + startId + "]"); + "], flags = [" + flags + "], startId = [" + startId + "]");
} }
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction()) if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
&& playerImpl.playQueue == null) { && player.getPlayQueue() == null) {
// Player is not working, no need to process media button's action // Player is not working, no need to process media button's action
return START_NOT_STICKY; return START_NOT_STICKY;
} }
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction()) if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
|| intent.getStringExtra(VideoPlayer.PLAY_QUEUE_KEY) != null) { || intent.getStringExtra(Player.PLAY_QUEUE_KEY) != null) {
NotificationUtil.getInstance().createNotificationAndStartForeground(playerImpl, this); NotificationUtil.getInstance().createNotificationAndStartForeground(player, this);
} }
playerImpl.handleIntent(intent); player.handleIntent(intent);
if (playerImpl.mediaSessionManager != null) { if (player.getMediaSessionManager() != null) {
playerImpl.mediaSessionManager.handleMediaButtonIntent(intent); player.getMediaSessionManager().handleMediaButtonIntent(intent);
} }
return START_NOT_STICKY; return START_NOT_STICKY;
} }
@ -141,20 +138,20 @@ public final class MainPlayer extends Service {
Log.d(TAG, "stop() called"); Log.d(TAG, "stop() called");
} }
if (playerImpl.getPlayer() != null) { if (!player.exoPlayerIsNull()) {
playerImpl.wasPlaying = playerImpl.getPlayer().getPlayWhenReady(); player.saveWasPlaying();
// Releases wifi & cpu, disables keepScreenOn, etc. // Releases wifi & cpu, disables keepScreenOn, etc.
if (!autoplayEnabled) { if (!autoplayEnabled) {
playerImpl.onPause(); player.pause();
} }
// We can't just pause the player here because it will make transition // We can't just pause the player here because it will make transition
// from one stream to a new stream not smooth // from one stream to a new stream not smooth
playerImpl.getPlayer().stop(false); player.smoothStopPlayer();
playerImpl.setRecovery(); player.setRecovery();
// Android TV will handle back button in case controls will be visible // Android TV will handle back button in case controls will be visible
// (one more additional unneeded click while the player is hidden) // (one more additional unneeded click while the player is hidden)
playerImpl.hideControls(0, 0); player.hideControls(0, 0);
playerImpl.onQueueClosed(); player.closeQueue();
// Notification shows information about old stream but if a user selects // Notification shows information about old stream but if a user selects
// a stream from backStack it's not actual anymore // a stream from backStack it's not actual anymore
// So we should hide the notification at all. // So we should hide the notification at all.
@ -168,7 +165,7 @@ public final class MainPlayer extends Service {
@Override @Override
public void onTaskRemoved(final Intent rootIntent) { public void onTaskRemoved(final Intent rootIntent) {
super.onTaskRemoved(rootIntent); super.onTaskRemoved(rootIntent);
if (!playerImpl.videoPlayerSelected()) { if (!player.videoPlayerSelected()) {
return; return;
} }
onDestroy(); onDestroy();
@ -181,7 +178,23 @@ public final class MainPlayer extends Service {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "destroy() called"); Log.d(TAG, "destroy() called");
} }
onClose();
if (player != null) {
// Exit from fullscreen when user closes the player via notification
if (player.isFullscreen()) {
player.toggleFullscreen();
}
removeViewFromParent();
player.saveStreamProgressState();
player.setRecovery();
player.stopActivityBinding();
player.removePopupFromView();
player.destroy();
}
NotificationUtil.getInstance().cancelNotificationAndStopForeground(this);
stopSelf();
} }
@Override @Override
@ -194,32 +207,6 @@ public final class MainPlayer extends Service {
return mBinder; return mBinder;
} }
/*//////////////////////////////////////////////////////////////////////////
// Actions
//////////////////////////////////////////////////////////////////////////*/
private void onClose() {
if (DEBUG) {
Log.d(TAG, "onClose() called");
}
if (playerImpl != null) {
// Exit from fullscreen when user closes the player via notification
if (playerImpl.isFullscreen()) {
playerImpl.toggleFullscreen();
}
removeViewFromParent();
playerImpl.setRecovery();
playerImpl.savePlaybackState();
playerImpl.stopActivityBinding();
playerImpl.removePopupFromView();
playerImpl.destroy();
}
NotificationUtil.getInstance().cancelNotificationAndStopForeground(this);
stopSelf();
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Utils // Utils
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -227,25 +214,25 @@ public final class MainPlayer extends Service {
boolean isLandscape() { boolean isLandscape() {
// DisplayMetrics from activity context knows about MultiWindow feature // DisplayMetrics from activity context knows about MultiWindow feature
// while DisplayMetrics from app context doesn't // while DisplayMetrics from app context doesn't
final DisplayMetrics metrics = (playerImpl != null final DisplayMetrics metrics = (player != null
&& playerImpl.getParentActivity() != null && player.getParentActivity() != null
? playerImpl.getParentActivity().getResources() ? player.getParentActivity().getResources()
: getResources()).getDisplayMetrics(); : getResources()).getDisplayMetrics();
return metrics.heightPixels < metrics.widthPixels; return metrics.heightPixels < metrics.widthPixels;
} }
@Nullable @Nullable
public View getView() { public View getView() {
if (playerImpl == null) { if (player == null) {
return null; return null;
} }
return playerImpl.getRootView(); return player.getRootView();
} }
public void removeViewFromParent() { public void removeViewFromParent() {
if (getView() != null && getView().getParent() != null) { if (getView() != null && getView().getParent() != null) {
if (playerImpl.getParentActivity() != null) { if (player.getParentActivity() != null) {
// This means view was added to fragment // This means view was added to fragment
final ViewGroup parent = (ViewGroup) getView().getParent(); final ViewGroup parent = (ViewGroup) getView().getParent();
parent.removeView(getView()); parent.removeView(getView());
@ -263,8 +250,8 @@ public final class MainPlayer extends Service {
return MainPlayer.this; return MainPlayer.this;
} }
public VideoPlayerImpl getPlayer() { public Player getPlayer() {
return MainPlayer.this.playerImpl; return MainPlayer.this.player;
} }
} }
} }

View file

@ -43,7 +43,7 @@ import static org.schabi.newpipe.player.MainPlayer.ACTION_SHUFFLE;
*/ */
public final class NotificationUtil { public final class NotificationUtil {
private static final String TAG = NotificationUtil.class.getSimpleName(); private static final String TAG = NotificationUtil.class.getSimpleName();
private static final boolean DEBUG = BasePlayer.DEBUG; private static final boolean DEBUG = Player.DEBUG;
private static final int NOTIFICATION_ID = 123789; private static final int NOTIFICATION_ID = 123789;
@Nullable private static NotificationUtil instance = null; @Nullable private static NotificationUtil instance = null;
@ -76,7 +76,7 @@ public final class NotificationUtil {
* @param forceRecreate whether to force the recreation of the notification even if it already * @param forceRecreate whether to force the recreation of the notification even if it already
* exists * exists
*/ */
synchronized void createNotificationIfNeededAndUpdate(final VideoPlayerImpl player, synchronized void createNotificationIfNeededAndUpdate(final Player player,
final boolean forceRecreate) { final boolean forceRecreate) {
if (forceRecreate || notificationBuilder == null) { if (forceRecreate || notificationBuilder == null) {
notificationBuilder = createNotification(player); notificationBuilder = createNotification(player);
@ -85,14 +85,14 @@ public final class NotificationUtil {
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
} }
private synchronized NotificationCompat.Builder createNotification( private synchronized NotificationCompat.Builder createNotification(final Player player) {
final VideoPlayerImpl player) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "createNotification()"); Log.d(TAG, "createNotification()");
} }
notificationManager = NotificationManagerCompat.from(player.context); notificationManager = NotificationManagerCompat.from(player.getContext());
final NotificationCompat.Builder builder = new NotificationCompat.Builder(player.context, final NotificationCompat.Builder builder =
player.context.getString(R.string.notification_channel_id)); new NotificationCompat.Builder(player.getContext(),
player.getContext().getString(R.string.notification_channel_id));
initializeNotificationSlots(player); initializeNotificationSlots(player);
@ -107,25 +107,25 @@ public final class NotificationUtil {
// build the compact slot indices array (need code to convert from Integer... because Java) // build the compact slot indices array (need code to convert from Integer... because Java)
final List<Integer> compactSlotList = NotificationConstants.getCompactSlotsFromPreferences( final List<Integer> compactSlotList = NotificationConstants.getCompactSlotsFromPreferences(
player.context, player.sharedPreferences, nonNothingSlotCount); player.getContext(), player.getPrefs(), nonNothingSlotCount);
final int[] compactSlots = new int[compactSlotList.size()]; final int[] compactSlots = new int[compactSlotList.size()];
for (int i = 0; i < compactSlotList.size(); i++) { for (int i = 0; i < compactSlotList.size(); i++) {
compactSlots[i] = compactSlotList.get(i); compactSlots[i] = compactSlotList.get(i);
} }
builder.setStyle(new androidx.media.app.NotificationCompat.MediaStyle() builder.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(player.mediaSessionManager.getSessionToken()) .setMediaSession(player.getMediaSessionManager().getSessionToken())
.setShowActionsInCompactView(compactSlots)) .setShowActionsInCompactView(compactSlots))
.setPriority(NotificationCompat.PRIORITY_HIGH) .setPriority(NotificationCompat.PRIORITY_HIGH)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setCategory(NotificationCompat.CATEGORY_TRANSPORT) .setCategory(NotificationCompat.CATEGORY_TRANSPORT)
.setShowWhen(false) .setShowWhen(false)
.setSmallIcon(R.drawable.ic_newpipe_triangle_white) .setSmallIcon(R.drawable.ic_newpipe_triangle_white)
.setColor(ContextCompat.getColor(player.context, R.color.dark_background_color)) .setColor(ContextCompat.getColor(player.getContext(),
.setColorized(player.sharedPreferences.getBoolean( R.color.dark_background_color))
player.context.getString(R.string.notification_colorize_key), .setColorized(player.getPrefs().getBoolean(
true)) player.getContext().getString(R.string.notification_colorize_key), true))
.setDeleteIntent(PendingIntent.getBroadcast(player.context, NOTIFICATION_ID, .setDeleteIntent(PendingIntent.getBroadcast(player.getContext(), NOTIFICATION_ID,
new Intent(ACTION_CLOSE), FLAG_UPDATE_CURRENT)); new Intent(ACTION_CLOSE), FLAG_UPDATE_CURRENT));
return builder; return builder;
@ -135,20 +135,20 @@ public final class NotificationUtil {
* Updates the notification builder and the button icons depending on the playback state. * Updates the notification builder and the button icons depending on the playback state.
* @param player the player currently open, to take data from * @param player the player currently open, to take data from
*/ */
private synchronized void updateNotification(final VideoPlayerImpl player) { private synchronized void updateNotification(final Player player) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "updateNotification()"); Log.d(TAG, "updateNotification()");
} }
// also update content intent, in case the user switched players // also update content intent, in case the user switched players
notificationBuilder.setContentIntent(PendingIntent.getActivity(player.context, notificationBuilder.setContentIntent(PendingIntent.getActivity(player.getContext(),
NOTIFICATION_ID, getIntentForNotification(player), FLAG_UPDATE_CURRENT)); NOTIFICATION_ID, getIntentForNotification(player), FLAG_UPDATE_CURRENT));
notificationBuilder.setContentTitle(player.getVideoTitle()); notificationBuilder.setContentTitle(player.getVideoTitle());
notificationBuilder.setContentText(player.getUploaderName()); notificationBuilder.setContentText(player.getUploaderName());
notificationBuilder.setTicker(player.getVideoTitle()); notificationBuilder.setTicker(player.getVideoTitle());
updateActions(notificationBuilder, player); updateActions(notificationBuilder, player);
final boolean showThumbnail = player.sharedPreferences.getBoolean( final boolean showThumbnail = player.getPrefs().getBoolean(
player.context.getString(R.string.show_thumbnail_key), true); player.getContext().getString(R.string.show_thumbnail_key), true);
if (showThumbnail) { if (showThumbnail) {
setLargeIcon(notificationBuilder, player); setLargeIcon(notificationBuilder, player);
} }
@ -174,7 +174,7 @@ public final class NotificationUtil {
} }
void createNotificationAndStartForeground(final VideoPlayerImpl player, final Service service) { void createNotificationAndStartForeground(final Player player, final Service service) {
if (notificationBuilder == null) { if (notificationBuilder == null) {
notificationBuilder = createNotification(player); notificationBuilder = createNotification(player);
} }
@ -203,17 +203,16 @@ public final class NotificationUtil {
// ACTIONS // ACTIONS
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
private void initializeNotificationSlots(final VideoPlayerImpl player) { private void initializeNotificationSlots(final Player player) {
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
notificationSlots[i] = player.sharedPreferences.getInt( notificationSlots[i] = player.getPrefs().getInt(
player.context.getString(NotificationConstants.SLOT_PREF_KEYS[i]), player.getContext().getString(NotificationConstants.SLOT_PREF_KEYS[i]),
NotificationConstants.SLOT_DEFAULTS[i]); NotificationConstants.SLOT_DEFAULTS[i]);
} }
} }
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
private void updateActions(final NotificationCompat.Builder builder, private void updateActions(final NotificationCompat.Builder builder, final Player player) {
final VideoPlayerImpl player) {
builder.mActions.clear(); builder.mActions.clear();
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
addAction(builder, player, notificationSlots[i]); addAction(builder, player, notificationSlots[i]);
@ -221,7 +220,7 @@ public final class NotificationUtil {
} }
private void addAction(final NotificationCompat.Builder builder, private void addAction(final NotificationCompat.Builder builder,
final VideoPlayerImpl player, final Player player,
@NotificationConstants.Action final int slot) { @NotificationConstants.Action final int slot) {
final NotificationCompat.Action action = getAction(player, slot); final NotificationCompat.Action action = getAction(player, slot);
if (action != null) { if (action != null) {
@ -231,7 +230,7 @@ public final class NotificationUtil {
@Nullable @Nullable
private NotificationCompat.Action getAction( private NotificationCompat.Action getAction(
final VideoPlayerImpl player, final Player player,
@NotificationConstants.Action final int selectedAction) { @NotificationConstants.Action final int selectedAction) {
final int baseActionIcon = NotificationConstants.ACTION_ICONS[selectedAction]; final int baseActionIcon = NotificationConstants.ACTION_ICONS[selectedAction];
switch (selectedAction) { switch (selectedAction) {
@ -252,7 +251,7 @@ public final class NotificationUtil {
R.string.exo_controls_fastforward_description, ACTION_FAST_FORWARD); R.string.exo_controls_fastforward_description, ACTION_FAST_FORWARD);
case NotificationConstants.SMART_REWIND_PREVIOUS: case NotificationConstants.SMART_REWIND_PREVIOUS:
if (player.playQueue != null && player.playQueue.size() > 1) { if (player.getPlayQueue() != null && player.getPlayQueue().size() > 1) {
return getAction(player, R.drawable.exo_notification_previous, return getAction(player, R.drawable.exo_notification_previous,
R.string.exo_controls_previous_description, ACTION_PLAY_PREVIOUS); R.string.exo_controls_previous_description, ACTION_PLAY_PREVIOUS);
} else { } else {
@ -261,7 +260,7 @@ public final class NotificationUtil {
} }
case NotificationConstants.SMART_FORWARD_NEXT: case NotificationConstants.SMART_FORWARD_NEXT:
if (player.playQueue != null && player.playQueue.size() > 1) { if (player.getPlayQueue() != null && player.getPlayQueue().size() > 1) {
return getAction(player, R.drawable.exo_notification_next, return getAction(player, R.drawable.exo_notification_next,
R.string.exo_controls_next_description, ACTION_PLAY_NEXT); R.string.exo_controls_next_description, ACTION_PLAY_NEXT);
} else { } else {
@ -270,23 +269,23 @@ public final class NotificationUtil {
} }
case NotificationConstants.PLAY_PAUSE_BUFFERING: case NotificationConstants.PLAY_PAUSE_BUFFERING:
if (player.getCurrentState() == BasePlayer.STATE_PREFLIGHT if (player.getCurrentState() == Player.STATE_PREFLIGHT
|| player.getCurrentState() == BasePlayer.STATE_BLOCKED || player.getCurrentState() == Player.STATE_BLOCKED
|| player.getCurrentState() == BasePlayer.STATE_BUFFERING) { || player.getCurrentState() == Player.STATE_BUFFERING) {
// null intent -> show hourglass icon that does nothing when clicked // null intent -> show hourglass icon that does nothing when clicked
return new NotificationCompat.Action(R.drawable.ic_hourglass_top_white_24dp_png, return new NotificationCompat.Action(R.drawable.ic_hourglass_top_white_24dp_png,
player.context.getString(R.string.notification_action_buffering), player.getContext().getString(R.string.notification_action_buffering),
null); null);
} }
case NotificationConstants.PLAY_PAUSE: case NotificationConstants.PLAY_PAUSE:
if (player.getCurrentState() == BasePlayer.STATE_COMPLETED) { if (player.getCurrentState() == Player.STATE_COMPLETED) {
return getAction(player, R.drawable.ic_replay_white_24dp_png, return getAction(player, R.drawable.ic_replay_white_24dp_png,
R.string.exo_controls_pause_description, ACTION_PLAY_PAUSE); R.string.exo_controls_pause_description, ACTION_PLAY_PAUSE);
} else if (player.isPlaying() } else if (player.isPlaying()
|| player.getCurrentState() == BasePlayer.STATE_PREFLIGHT || player.getCurrentState() == Player.STATE_PREFLIGHT
|| player.getCurrentState() == BasePlayer.STATE_BLOCKED || player.getCurrentState() == Player.STATE_BLOCKED
|| player.getCurrentState() == BasePlayer.STATE_BUFFERING) { || player.getCurrentState() == Player.STATE_BUFFERING) {
return getAction(player, R.drawable.exo_notification_pause, return getAction(player, R.drawable.exo_notification_pause,
R.string.exo_controls_pause_description, ACTION_PLAY_PAUSE); R.string.exo_controls_pause_description, ACTION_PLAY_PAUSE);
} else { } else {
@ -307,7 +306,7 @@ public final class NotificationUtil {
} }
case NotificationConstants.SHUFFLE: case NotificationConstants.SHUFFLE:
if (player.playQueue != null && player.playQueue.isShuffled()) { if (player.getPlayQueue() != null && player.getPlayQueue().isShuffled()) {
return getAction(player, R.drawable.exo_controls_shuffle_on, return getAction(player, R.drawable.exo_controls_shuffle_on,
R.string.exo_controls_shuffle_on_description, ACTION_SHUFFLE); R.string.exo_controls_shuffle_on_description, ACTION_SHUFFLE);
} else { } else {
@ -326,23 +325,23 @@ public final class NotificationUtil {
} }
} }
private NotificationCompat.Action getAction(final VideoPlayerImpl player, private NotificationCompat.Action getAction(final Player player,
@DrawableRes final int drawable, @DrawableRes final int drawable,
@StringRes final int title, @StringRes final int title,
final String intentAction) { final String intentAction) {
return new NotificationCompat.Action(drawable, player.context.getString(title), return new NotificationCompat.Action(drawable, player.getContext().getString(title),
PendingIntent.getBroadcast(player.context, NOTIFICATION_ID, PendingIntent.getBroadcast(player.getContext(), NOTIFICATION_ID,
new Intent(intentAction), FLAG_UPDATE_CURRENT)); new Intent(intentAction), FLAG_UPDATE_CURRENT));
} }
private Intent getIntentForNotification(final VideoPlayerImpl player) { private Intent getIntentForNotification(final Player player) {
if (player.audioPlayerSelected() || player.popupPlayerSelected()) { if (player.audioPlayerSelected() || player.popupPlayerSelected()) {
// Means we play in popup or audio only. Let's show the play queue // Means we play in popup or audio only. Let's show the play queue
return NavigationHelper.getPlayQueueActivityIntent(player.context); return NavigationHelper.getPlayQueueActivityIntent(player.getContext());
} else { } else {
// We are playing in fragment. Don't open another activity just show fragment. That's it // We are playing in fragment. Don't open another activity just show fragment. That's it
final Intent intent = NavigationHelper.getPlayerIntent( final Intent intent = NavigationHelper.getPlayerIntent(
player.context, MainActivity.class, null, true); player.getContext(), MainActivity.class, null, true);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_MAIN); intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.addCategory(Intent.CATEGORY_LAUNCHER);
@ -355,10 +354,9 @@ public final class NotificationUtil {
// BITMAP // BITMAP
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
private void setLargeIcon(final NotificationCompat.Builder builder, private void setLargeIcon(final NotificationCompat.Builder builder, final Player player) {
final VideoPlayerImpl player) { final boolean scaleImageToSquareAspectRatio = player.getPrefs().getBoolean(
final boolean scaleImageToSquareAspectRatio = player.sharedPreferences.getBoolean( player.getContext().getString(R.string.scale_to_square_image_in_notifications_key),
player.context.getString(R.string.scale_to_square_image_in_notifications_key),
false); false);
if (scaleImageToSquareAspectRatio) { if (scaleImageToSquareAspectRatio) {
builder.setLargeIcon(getBitmapWithSquareAspectRatio(player.getThumbnail())); builder.setLargeIcon(getBitmapWithSquareAspectRatio(player.getThumbnail()));

View file

@ -16,13 +16,11 @@ import android.widget.PopupMenu;
import android.widget.SeekBar; import android.widget.SeekBar;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.ActivityPlayerQueueControlBinding; import org.schabi.newpipe.databinding.ActivityPlayerQueueControlBinding;
@ -49,19 +47,21 @@ import java.util.List;
import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed; import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
public abstract class ServicePlayerActivity extends AppCompatActivity public final class PlayQueueActivity extends AppCompatActivity
implements PlayerEventListener, SeekBar.OnSeekBarChangeListener, implements PlayerEventListener, SeekBar.OnSeekBarChangeListener,
View.OnClickListener, PlaybackParameterDialog.Callback { View.OnClickListener, PlaybackParameterDialog.Callback {
private static final String TAG = PlayQueueActivity.class.getSimpleName();
private static final int RECYCLER_ITEM_POPUP_MENU_GROUP_ID = 47; private static final int RECYCLER_ITEM_POPUP_MENU_GROUP_ID = 47;
private static final int SMOOTH_SCROLL_MAXIMUM_DISTANCE = 80; private static final int SMOOTH_SCROLL_MAXIMUM_DISTANCE = 80;
protected BasePlayer player; protected Player player;
private boolean serviceBound; private boolean serviceBound;
private ServiceConnection serviceConnection; private ServiceConnection serviceConnection;
private boolean seeking; private boolean seeking;
private boolean redraw;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Views // Views
@ -73,24 +73,6 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
private Menu menu; private Menu menu;
////////////////////////////////////////////////////////////////////////////
// Abstracts
////////////////////////////////////////////////////////////////////////////
public abstract String getTag();
public abstract String getSupportActionTitle();
public abstract Intent getBindIntent();
public abstract void startPlayerListener();
public abstract void stopPlayerListener();
public abstract int getPlayerOptionMenuResource();
public abstract void setupMenu(Menu m);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Activity Lifecycle // Activity Lifecycle
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -107,35 +89,32 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
setSupportActionBar(queueControlBinding.toolbar); setSupportActionBar(queueControlBinding.toolbar);
if (getSupportActionBar() != null) { if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(getSupportActionTitle()); getSupportActionBar().setTitle(R.string.title_activity_play_queue);
} }
serviceConnection = getServiceConnection(); serviceConnection = getServiceConnection();
bind(); bind();
} }
@Override
protected void onResume() {
super.onResume();
if (redraw) {
ActivityCompat.recreate(this);
redraw = false;
}
}
@Override @Override
public boolean onCreateOptionsMenu(final Menu m) { public boolean onCreateOptionsMenu(final Menu m) {
this.menu = m; this.menu = m;
getMenuInflater().inflate(R.menu.menu_play_queue, m); getMenuInflater().inflate(R.menu.menu_play_queue, m);
getMenuInflater().inflate(getPlayerOptionMenuResource(), m); getMenuInflater().inflate(R.menu.menu_play_queue_bg, m);
onMaybeMuteChanged(); onMaybeMuteChanged();
onPlaybackParameterChanged(player.getPlaybackParameters());
return true; return true;
} }
// Allow to setup visibility of menuItems // Allow to setup visibility of menuItems
@Override @Override
public boolean onPrepareOptionsMenu(final Menu m) { public boolean onPrepareOptionsMenu(final Menu m) {
setupMenu(m); if (player != null) {
menu.findItem(R.id.action_switch_popup)
.setVisible(!player.popupPlayerSelected());
menu.findItem(R.id.action_switch_background)
.setVisible(!player.audioPlayerSelected());
}
return super.onPrepareOptionsMenu(m); return super.onPrepareOptionsMenu(m);
} }
@ -167,14 +146,14 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
case R.id.action_switch_popup: case R.id.action_switch_popup:
if (PermissionHelper.isPopupEnabled(this)) { if (PermissionHelper.isPopupEnabled(this)) {
this.player.setRecovery(); this.player.setRecovery();
NavigationHelper.playOnPopupPlayer(this, player.playQueue, true); NavigationHelper.playOnPopupPlayer(this, player.getPlayQueue(), true);
} else { } else {
PermissionHelper.showPopupEnablementToast(this); PermissionHelper.showPopupEnablementToast(this);
} }
return true; return true;
case R.id.action_switch_background: case R.id.action_switch_background:
this.player.setRecovery(); this.player.setRecovery();
NavigationHelper.playOnBackgroundPlayer(this, player.playQueue, true); NavigationHelper.playOnBackgroundPlayer(this, player.getPlayQueue(), true);
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
@ -191,7 +170,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
private void bind() { private void bind() {
final boolean success = bindService(getBindIntent(), serviceConnection, BIND_AUTO_CREATE); final Intent bindIntent = new Intent(this, MainPlayer.class);
final boolean success = bindService(bindIntent, serviceConnection, BIND_AUTO_CREATE);
if (!success) { if (!success) {
unbindService(serviceConnection); unbindService(serviceConnection);
} }
@ -202,7 +182,9 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
if (serviceBound) { if (serviceBound) {
unbindService(serviceConnection); unbindService(serviceConnection);
serviceBound = false; serviceBound = false;
stopPlayerListener(); if (player != null) {
player.removeActivityListener(this);
}
if (player != null && player.getPlayQueueAdapter() != null) { if (player != null && player.getPlayQueueAdapter() != null) {
player.getPlayQueueAdapter().unsetSelectedListener(); player.getPlayQueueAdapter().unsetSelectedListener();
@ -221,12 +203,12 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
return new ServiceConnection() { return new ServiceConnection() {
@Override @Override
public void onServiceDisconnected(final ComponentName name) { public void onServiceDisconnected(final ComponentName name) {
Log.d(getTag(), "Player service is disconnected"); Log.d(TAG, "Player service is disconnected");
} }
@Override @Override
public void onServiceConnected(final ComponentName name, final IBinder service) { public void onServiceConnected(final ComponentName name, final IBinder service) {
Log.d(getTag(), "Player service is connected"); Log.d(TAG, "Player service is connected");
if (service instanceof PlayerServiceBinder) { if (service instanceof PlayerServiceBinder) {
player = ((PlayerServiceBinder) service).getPlayerInstance(); player = ((PlayerServiceBinder) service).getPlayerInstance();
@ -235,12 +217,14 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
} }
if (player == null || player.getPlayQueue() == null if (player == null || player.getPlayQueue() == null
|| player.getPlayQueueAdapter() == null || player.getPlayer() == null) { || player.getPlayQueueAdapter() == null || player.exoPlayerIsNull()) {
unbind(); unbind();
finish(); finish();
} else { } else {
buildComponents(); buildComponents();
startPlayerListener(); if (player != null) {
player.setActivityListener(PlayQueueActivity.this);
}
} }
} }
}; };
@ -375,7 +359,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
@Override @Override
public void selected(final PlayQueueItem item, final View view) { public void selected(final PlayQueueItem item, final View view) {
if (player != null) { if (player != null) {
player.onSelected(item); player.selectQueueItem(item);
} }
} }
@ -436,15 +420,15 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
if (view.getId() == queueControlBinding.controlRepeat.getId()) { if (view.getId() == queueControlBinding.controlRepeat.getId()) {
player.onRepeatClicked(); player.onRepeatClicked();
} else if (view.getId() == queueControlBinding.controlBackward.getId()) { } else if (view.getId() == queueControlBinding.controlBackward.getId()) {
player.onPlayPrevious(); player.playPrevious();
} else if (view.getId() == queueControlBinding.controlFastRewind.getId()) { } else if (view.getId() == queueControlBinding.controlFastRewind.getId()) {
player.onFastRewind(); player.fastRewind();
} else if (view.getId() == queueControlBinding.controlPlayPause.getId()) { } else if (view.getId() == queueControlBinding.controlPlayPause.getId()) {
player.onPlayPause(); player.playPause();
} else if (view.getId() == queueControlBinding.controlFastForward.getId()) { } else if (view.getId() == queueControlBinding.controlFastForward.getId()) {
player.onFastForward(); player.fastForward();
} else if (view.getId() == queueControlBinding.controlForward.getId()) { } else if (view.getId() == queueControlBinding.controlForward.getId()) {
player.onPlayNext(); player.playNext();
} else if (view.getId() == queueControlBinding.controlShuffle.getId()) { } else if (view.getId() == queueControlBinding.controlShuffle.getId()) {
player.onShuffleClicked(); player.onShuffleClicked();
} else if (view.getId() == queueControlBinding.metadata.getId()) { } else if (view.getId() == queueControlBinding.metadata.getId()) {
@ -463,7 +447,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
return; return;
} }
PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), player.getPlaybackPitch(), PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), player.getPlaybackPitch(),
player.getPlaybackSkipSilence(), this).show(getSupportFragmentManager(), getTag()); player.getPlaybackSkipSilence(), this).show(getSupportFragmentManager(), TAG);
} }
@Override @Override
@ -517,10 +501,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
final PlaylistAppendDialog d = PlaylistAppendDialog.fromPlayQueueItems(playlist); final PlaylistAppendDialog d = PlaylistAppendDialog.fromPlayQueueItems(playlist);
PlaylistAppendDialog.onPlaylistFound(getApplicationContext(), PlaylistAppendDialog.onPlaylistFound(getApplicationContext(),
() -> d.show(getSupportFragmentManager(), getTag()), () -> d.show(getSupportFragmentManager(), TAG),
() -> PlaylistCreationDialog.newInstance(d) () -> PlaylistCreationDialog.newInstance(d).show(getSupportFragmentManager(), TAG));
.show(getSupportFragmentManager(), getTag()
));
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -616,15 +598,15 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
private void onStateChanged(final int state) { private void onStateChanged(final int state) {
switch (state) { switch (state) {
case BasePlayer.STATE_PAUSED: case Player.STATE_PAUSED:
queueControlBinding.controlPlayPause queueControlBinding.controlPlayPause
.setImageResource(R.drawable.ic_play_arrow_white_24dp); .setImageResource(R.drawable.ic_play_arrow_white_24dp);
break; break;
case BasePlayer.STATE_PLAYING: case Player.STATE_PLAYING:
queueControlBinding.controlPlayPause queueControlBinding.controlPlayPause
.setImageResource(R.drawable.ic_pause_white_24dp); .setImageResource(R.drawable.ic_pause_white_24dp);
break; break;
case BasePlayer.STATE_COMPLETED: case Player.STATE_COMPLETED:
queueControlBinding.controlPlayPause queueControlBinding.controlPlayPause
.setImageResource(R.drawable.ic_replay_white_24dp); .setImageResource(R.drawable.ic_replay_white_24dp);
break; break;
@ -633,9 +615,9 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
} }
switch (state) { switch (state) {
case BasePlayer.STATE_PAUSED: case Player.STATE_PAUSED:
case BasePlayer.STATE_PLAYING: case Player.STATE_PLAYING:
case BasePlayer.STATE_COMPLETED: case Player.STATE_COMPLETED:
queueControlBinding.controlPlayPause.setClickable(true); queueControlBinding.controlPlayPause.setClickable(true);
queueControlBinding.controlPlayPause.setVisibility(View.VISIBLE); queueControlBinding.controlPlayPause.setVisibility(View.VISIBLE);
queueControlBinding.controlProgressBar.setVisibility(View.GONE); queueControlBinding.controlProgressBar.setVisibility(View.GONE);
@ -650,15 +632,15 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
private void onPlayModeChanged(final int repeatMode, final boolean shuffled) { private void onPlayModeChanged(final int repeatMode, final boolean shuffled) {
switch (repeatMode) { switch (repeatMode) {
case Player.REPEAT_MODE_OFF: case com.google.android.exoplayer2.Player.REPEAT_MODE_OFF:
queueControlBinding.controlRepeat queueControlBinding.controlRepeat
.setImageResource(R.drawable.exo_controls_repeat_off); .setImageResource(R.drawable.exo_controls_repeat_off);
break; break;
case Player.REPEAT_MODE_ONE: case com.google.android.exoplayer2.Player.REPEAT_MODE_ONE:
queueControlBinding.controlRepeat queueControlBinding.controlRepeat
.setImageResource(R.drawable.exo_controls_repeat_one); .setImageResource(R.drawable.exo_controls_repeat_one);
break; break;
case Player.REPEAT_MODE_ALL: case com.google.android.exoplayer2.Player.REPEAT_MODE_ALL:
queueControlBinding.controlRepeat queueControlBinding.controlRepeat
.setImageResource(R.drawable.exo_controls_repeat_all); .setImageResource(R.drawable.exo_controls_repeat_all);
break; break;
@ -700,9 +682,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
// using rootView.getContext() because getApplicationContext() didn't work // using rootView.getContext() because getApplicationContext() didn't work
final Context context = queueControlBinding.getRoot().getContext(); final Context context = queueControlBinding.getRoot().getContext();
item.setIcon(ThemeHelper.resolveResourceIdFromAttr(context, item.setIcon(ThemeHelper.resolveResourceIdFromAttr(context,
player.isMuted() player.isMuted() ? R.attr.ic_volume_off : R.attr.ic_volume_up));
? R.attr.ic_volume_off
: R.attr.ic_volume_up));
} }
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -5,13 +5,13 @@ import android.os.Binder;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
class PlayerServiceBinder extends Binder { class PlayerServiceBinder extends Binder {
private final BasePlayer basePlayer; private final Player player;
PlayerServiceBinder(@NonNull final BasePlayer basePlayer) { PlayerServiceBinder(@NonNull final Player player) {
this.basePlayer = basePlayer; this.player = player;
} }
BasePlayer getPlayerInstance() { Player getPlayerInstance() {
return basePlayer; return player;
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -7,10 +7,10 @@ import android.view.GestureDetector
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewConfiguration import android.view.ViewConfiguration
import org.schabi.newpipe.player.BasePlayer
import org.schabi.newpipe.player.MainPlayer import org.schabi.newpipe.player.MainPlayer
import org.schabi.newpipe.player.VideoPlayerImpl import org.schabi.newpipe.player.Player
import org.schabi.newpipe.player.helper.PlayerHelper import org.schabi.newpipe.player.helper.PlayerHelper
import org.schabi.newpipe.player.helper.PlayerHelper.savePopupPositionAndSizeToPrefs
import org.schabi.newpipe.util.AnimationUtils import org.schabi.newpipe.util.AnimationUtils
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.hypot import kotlin.math.hypot
@ -18,14 +18,14 @@ import kotlin.math.max
import kotlin.math.min import kotlin.math.min
/** /**
* Base gesture handling for [VideoPlayerImpl] * Base gesture handling for [Player]
* *
* This class contains the logic for the player gestures like View preparations * This class contains the logic for the player gestures like View preparations
* and provides some abstract methods to make it easier separating the logic from the UI. * and provides some abstract methods to make it easier separating the logic from the UI.
*/ */
abstract class BasePlayerGestureListener( abstract class BasePlayerGestureListener(
@JvmField @JvmField
protected val playerImpl: VideoPlayerImpl, protected val player: Player,
@JvmField @JvmField
protected val service: MainPlayer protected val service: MainPlayer
) : GestureDetector.SimpleOnGestureListener(), View.OnTouchListener { ) : GestureDetector.SimpleOnGestureListener(), View.OnTouchListener {
@ -78,7 +78,7 @@ abstract class BasePlayerGestureListener(
// /////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////
override fun onTouch(v: View, event: MotionEvent): Boolean { override fun onTouch(v: View, event: MotionEvent): Boolean {
return if (playerImpl.popupPlayerSelected()) { return if (player.popupPlayerSelected()) {
onTouchInPopup(v, event) onTouchInPopup(v, event)
} else { } else {
onTouchInMain(v, event) onTouchInMain(v, event)
@ -86,14 +86,14 @@ abstract class BasePlayerGestureListener(
} }
private fun onTouchInMain(v: View, event: MotionEvent): Boolean { private fun onTouchInMain(v: View, event: MotionEvent): Boolean {
playerImpl.gestureDetector.onTouchEvent(event) player.gestureDetector.onTouchEvent(event)
if (event.action == MotionEvent.ACTION_UP && isMovingInMain) { if (event.action == MotionEvent.ACTION_UP && isMovingInMain) {
isMovingInMain = false isMovingInMain = false
onScrollEnd(MainPlayer.PlayerType.VIDEO, event) onScrollEnd(MainPlayer.PlayerType.VIDEO, event)
} }
return when (event.action) { return when (event.action) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
v.parent.requestDisallowInterceptTouchEvent(playerImpl.isFullscreen) v.parent.requestDisallowInterceptTouchEvent(player.isFullscreen)
true true
} }
MotionEvent.ACTION_UP -> { MotionEvent.ACTION_UP -> {
@ -105,7 +105,7 @@ abstract class BasePlayerGestureListener(
} }
private fun onTouchInPopup(v: View, event: MotionEvent): Boolean { private fun onTouchInPopup(v: View, event: MotionEvent): Boolean {
playerImpl.gestureDetector.onTouchEvent(event) player.gestureDetector.onTouchEvent(event)
if (event.pointerCount == 2 && !isMovingInPopup && !isResizing) { if (event.pointerCount == 2 && !isMovingInPopup && !isResizing) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onTouch() 2 finger pointer detected, enabling resizing.") Log.d(TAG, "onTouch() 2 finger pointer detected, enabling resizing.")
@ -157,10 +157,10 @@ abstract class BasePlayerGestureListener(
initSecPointerY = (-1).toFloat() initSecPointerY = (-1).toFloat()
onPopupResizingEnd() onPopupResizingEnd()
playerImpl.changeState(playerImpl.currentState) player.changeState(player.currentState)
} }
if (!playerImpl.isPopupClosing) { if (!player.isPopupClosing) {
playerImpl.savePositionAndSize() savePopupPositionAndSizeToPrefs(player)
} }
} }
@ -190,19 +190,15 @@ abstract class BasePlayerGestureListener(
event.getY(0) - event.getY(1).toDouble() event.getY(0) - event.getY(1).toDouble()
) )
val popupWidth = playerImpl.popupWidth.toDouble() val popupWidth = player.popupLayoutParams!!.width.toDouble()
// change co-ordinates of popup so the center stays at the same position // change co-ordinates of popup so the center stays at the same position
val newWidth = popupWidth * currentPointerDistance / initPointerDistance val newWidth = popupWidth * currentPointerDistance / initPointerDistance
initPointerDistance = currentPointerDistance initPointerDistance = currentPointerDistance
playerImpl.popupLayoutParams.x += ((popupWidth - newWidth) / 2.0).toInt() player.popupLayoutParams!!.x += ((popupWidth - newWidth) / 2.0).toInt()
playerImpl.checkPopupPositionBounds() player.checkPopupPositionBounds()
playerImpl.updateScreenSize() player.updateScreenSize()
player.changePopupSize(min(player.screenWidth.toDouble(), newWidth).toInt())
playerImpl.updatePopupSize(
min(playerImpl.screenWidth.toDouble(), newWidth).toInt(),
-1
)
return true return true
} }
} }
@ -222,7 +218,7 @@ abstract class BasePlayerGestureListener(
return true return true
} }
return if (playerImpl.popupPlayerSelected()) return if (player.popupPlayerSelected())
onDownInPopup(e) onDownInPopup(e)
else else
true true
@ -231,12 +227,10 @@ abstract class BasePlayerGestureListener(
private fun onDownInPopup(e: MotionEvent): Boolean { private fun onDownInPopup(e: MotionEvent): Boolean {
// Fix popup position when the user touch it, it may have the wrong one // Fix popup position when the user touch it, it may have the wrong one
// because the soft input is visible (the draggable area is currently resized). // because the soft input is visible (the draggable area is currently resized).
playerImpl.updateScreenSize() player.updateScreenSize()
playerImpl.checkPopupPositionBounds() player.checkPopupPositionBounds()
initialPopupX = playerImpl.popupLayoutParams.x initialPopupX = player.popupLayoutParams!!.x
initialPopupY = playerImpl.popupLayoutParams.y initialPopupY = player.popupLayoutParams!!.y
playerImpl.popupWidth = playerImpl.popupLayoutParams.width.toFloat()
playerImpl.popupHeight = playerImpl.popupLayoutParams.height.toFloat()
return super.onDown(e) return super.onDown(e)
} }
@ -255,15 +249,15 @@ abstract class BasePlayerGestureListener(
if (isDoubleTapping) if (isDoubleTapping)
return true return true
if (playerImpl.popupPlayerSelected()) { if (player.popupPlayerSelected()) {
if (playerImpl.player == null) if (player.exoPlayerIsNull())
return false return false
onSingleTap(MainPlayer.PlayerType.POPUP) onSingleTap(MainPlayer.PlayerType.POPUP)
return true return true
} else { } else {
super.onSingleTapConfirmed(e) super.onSingleTapConfirmed(e)
if (playerImpl.currentState == BasePlayer.STATE_BLOCKED) if (player.currentState == Player.STATE_BLOCKED)
return true return true
onSingleTap(MainPlayer.PlayerType.VIDEO) onSingleTap(MainPlayer.PlayerType.VIDEO)
@ -272,10 +266,10 @@ abstract class BasePlayerGestureListener(
} }
override fun onLongPress(e: MotionEvent?) { override fun onLongPress(e: MotionEvent?) {
if (playerImpl.popupPlayerSelected()) { if (player.popupPlayerSelected()) {
playerImpl.updateScreenSize() player.updateScreenSize()
playerImpl.checkPopupPositionBounds() player.checkPopupPositionBounds()
playerImpl.updatePopupSize(playerImpl.screenWidth.toInt(), -1) player.changePopupSize(player.screenWidth.toInt())
} }
} }
@ -285,7 +279,7 @@ abstract class BasePlayerGestureListener(
distanceX: Float, distanceX: Float,
distanceY: Float distanceY: Float
): Boolean { ): Boolean {
return if (playerImpl.popupPlayerSelected()) { return if (player.popupPlayerSelected()) {
onScrollInPopup(initialEvent, movingEvent, distanceX, distanceY) onScrollInPopup(initialEvent, movingEvent, distanceX, distanceY)
} else { } else {
onScrollInMain(initialEvent, movingEvent, distanceX, distanceY) onScrollInMain(initialEvent, movingEvent, distanceX, distanceY)
@ -298,19 +292,18 @@ abstract class BasePlayerGestureListener(
velocityX: Float, velocityX: Float,
velocityY: Float velocityY: Float
): Boolean { ): Boolean {
return if (playerImpl.popupPlayerSelected()) { return if (player.popupPlayerSelected()) {
val absVelocityX = abs(velocityX) val absVelocityX = abs(velocityX)
val absVelocityY = abs(velocityY) val absVelocityY = abs(velocityY)
if (absVelocityX.coerceAtLeast(absVelocityY) > tossFlingVelocity) { if (absVelocityX.coerceAtLeast(absVelocityY) > tossFlingVelocity) {
if (absVelocityX > tossFlingVelocity) { if (absVelocityX > tossFlingVelocity) {
playerImpl.popupLayoutParams.x = velocityX.toInt() player.popupLayoutParams!!.x = velocityX.toInt()
} }
if (absVelocityY > tossFlingVelocity) { if (absVelocityY > tossFlingVelocity) {
playerImpl.popupLayoutParams.y = velocityY.toInt() player.popupLayoutParams!!.y = velocityY.toInt()
} }
playerImpl.checkPopupPositionBounds() player.checkPopupPositionBounds()
playerImpl.windowManager player.windowManager!!.updateViewLayout(player.rootView, player.popupLayoutParams)
.updateViewLayout(playerImpl.rootView, playerImpl.popupLayoutParams)
return true return true
} }
return false return false
@ -326,13 +319,13 @@ abstract class BasePlayerGestureListener(
distanceY: Float distanceY: Float
): Boolean { ): Boolean {
if (!playerImpl.isFullscreen) { if (!player.isFullscreen) {
return false return false
} }
val isTouchingStatusBar: Boolean = initialEvent.y < getStatusBarHeight(service) val isTouchingStatusBar: Boolean = initialEvent.y < getStatusBarHeight(service)
val isTouchingNavigationBar: Boolean = val isTouchingNavigationBar: Boolean =
initialEvent.y > (playerImpl.rootView.height - getNavigationBarHeight(service)) initialEvent.y > (player.rootView.height - getNavigationBarHeight(service))
if (isTouchingStatusBar || isTouchingNavigationBar) { if (isTouchingStatusBar || isTouchingNavigationBar) {
return false return false
} }
@ -340,7 +333,7 @@ abstract class BasePlayerGestureListener(
val insideThreshold = abs(movingEvent.y - initialEvent.y) <= MOVEMENT_THRESHOLD val insideThreshold = abs(movingEvent.y - initialEvent.y) <= MOVEMENT_THRESHOLD
if ( if (
!isMovingInMain && (insideThreshold || abs(distanceX) > abs(distanceY)) || !isMovingInMain && (insideThreshold || abs(distanceX) > abs(distanceY)) ||
playerImpl.currentState == BasePlayer.STATE_COMPLETED player.currentState == Player.STATE_COMPLETED
) { ) {
return false return false
} }
@ -371,7 +364,7 @@ abstract class BasePlayerGestureListener(
} }
if (!isMovingInPopup) { if (!isMovingInPopup) {
AnimationUtils.animateView(playerImpl.closeButton, true, 200) AnimationUtils.animateView(player.closeOverlayButton, true, 200)
} }
isMovingInPopup = true isMovingInPopup = true
@ -381,20 +374,20 @@ abstract class BasePlayerGestureListener(
val diffY: Float = (movingEvent.rawY - initialEvent.rawY) val diffY: Float = (movingEvent.rawY - initialEvent.rawY)
var posY: Float = (initialPopupY + diffY) var posY: Float = (initialPopupY + diffY)
if (posX > playerImpl.screenWidth - playerImpl.popupWidth) { if (posX > player.screenWidth - player.popupLayoutParams!!.width) {
posX = (playerImpl.screenWidth - playerImpl.popupWidth) posX = (player.screenWidth - player.popupLayoutParams!!.width)
} else if (posX < 0) { } else if (posX < 0) {
posX = 0f posX = 0f
} }
if (posY > playerImpl.screenHeight - playerImpl.popupHeight) { if (posY > player.screenHeight - player.popupLayoutParams!!.height) {
posY = (playerImpl.screenHeight - playerImpl.popupHeight) posY = (player.screenHeight - player.popupLayoutParams!!.height)
} else if (posY < 0) { } else if (posY < 0) {
posY = 0f posY = 0f
} }
playerImpl.popupLayoutParams.x = posX.toInt() player.popupLayoutParams!!.x = posX.toInt()
playerImpl.popupLayoutParams.y = posY.toInt() player.popupLayoutParams!!.y = posY.toInt()
onScroll( onScroll(
MainPlayer.PlayerType.POPUP, MainPlayer.PlayerType.POPUP,
@ -405,8 +398,7 @@ abstract class BasePlayerGestureListener(
distanceY distanceY
) )
playerImpl.windowManager player.windowManager!!.updateViewLayout(player.rootView, player.popupLayoutParams)
.updateViewLayout(playerImpl.rootView, playerImpl.popupLayoutParams)
return true return true
} }
@ -474,16 +466,16 @@ abstract class BasePlayerGestureListener(
// /////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////
private fun getDisplayPortion(e: MotionEvent): DisplayPortion { private fun getDisplayPortion(e: MotionEvent): DisplayPortion {
return if (playerImpl.playerType == MainPlayer.PlayerType.POPUP) { return if (player.playerType == MainPlayer.PlayerType.POPUP) {
when { when {
e.x < playerImpl.popupWidth / 3.0 -> DisplayPortion.LEFT e.x < player.popupLayoutParams!!.width / 3.0 -> DisplayPortion.LEFT
e.x > playerImpl.popupWidth * 2.0 / 3.0 -> DisplayPortion.RIGHT e.x > player.popupLayoutParams!!.width * 2.0 / 3.0 -> DisplayPortion.RIGHT
else -> DisplayPortion.MIDDLE else -> DisplayPortion.MIDDLE
} }
} else /* MainPlayer.PlayerType.VIDEO */ { } else /* MainPlayer.PlayerType.VIDEO */ {
when { when {
e.x < playerImpl.rootView.width / 3.0 -> DisplayPortion.LEFT e.x < player.rootView.width / 3.0 -> DisplayPortion.LEFT
e.x > playerImpl.rootView.width * 2.0 / 3.0 -> DisplayPortion.RIGHT e.x > player.rootView.width * 2.0 / 3.0 -> DisplayPortion.RIGHT
else -> DisplayPortion.MIDDLE else -> DisplayPortion.MIDDLE
} }
} }
@ -491,14 +483,14 @@ abstract class BasePlayerGestureListener(
// Currently needed for scrolling since there is no action more the middle portion // Currently needed for scrolling since there is no action more the middle portion
private fun getDisplayHalfPortion(e: MotionEvent): DisplayPortion { private fun getDisplayHalfPortion(e: MotionEvent): DisplayPortion {
return if (playerImpl.playerType == MainPlayer.PlayerType.POPUP) { return if (player.playerType == MainPlayer.PlayerType.POPUP) {
when { when {
e.x < playerImpl.popupWidth / 2.0 -> DisplayPortion.LEFT_HALF e.x < player.popupLayoutParams!!.width / 2.0 -> DisplayPortion.LEFT_HALF
else -> DisplayPortion.RIGHT_HALF else -> DisplayPortion.RIGHT_HALF
} }
} else /* MainPlayer.PlayerType.VIDEO */ { } else /* MainPlayer.PlayerType.VIDEO */ {
when { when {
e.x < playerImpl.rootView.width / 2.0 -> DisplayPortion.LEFT_HALF e.x < player.rootView.width / 2.0 -> DisplayPortion.LEFT_HALF
else -> DisplayPortion.RIGHT_HALF else -> DisplayPortion.RIGHT_HALF
} }
} }
@ -522,7 +514,7 @@ abstract class BasePlayerGestureListener(
companion object { companion object {
private const val TAG = "BasePlayerGestListener" private const val TAG = "BasePlayerGestListener"
private val DEBUG = BasePlayer.DEBUG private val DEBUG = Player.DEBUG
private const val DOUBLE_TAP_DELAY = 550L private const val DOUBLE_TAP_DELAY = 550L
private const val MOVEMENT_THRESHOLD = 40 private const val MOVEMENT_THRESHOLD = 40

View file

@ -11,15 +11,15 @@ import android.widget.ProgressBar;
import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.content.res.AppCompatResources;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.player.BasePlayer;
import org.schabi.newpipe.player.MainPlayer; import org.schabi.newpipe.player.MainPlayer;
import org.schabi.newpipe.player.VideoPlayerImpl; import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import static org.schabi.newpipe.player.BasePlayer.STATE_PLAYING; import static org.schabi.newpipe.player.Player.STATE_PLAYING;
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_DURATION; import static org.schabi.newpipe.player.Player.DEFAULT_CONTROLS_DURATION;
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME; import static org.schabi.newpipe.player.Player.DEFAULT_CONTROLS_HIDE_TIME;
import static org.schabi.newpipe.util.AnimationUtils.Type.SCALE_AND_ALPHA; import static org.schabi.newpipe.util.AnimationUtils.Type.SCALE_AND_ALPHA;
import static org.schabi.newpipe.util.AnimationUtils.animateView; import static org.schabi.newpipe.util.AnimationUtils.animateView;
@ -33,14 +33,14 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class PlayerGestureListener public class PlayerGestureListener
extends BasePlayerGestureListener extends BasePlayerGestureListener
implements View.OnTouchListener { implements View.OnTouchListener {
private static final String TAG = ".PlayerGestureListener"; private static final String TAG = PlayerGestureListener.class.getSimpleName();
private static final boolean DEBUG = BasePlayer.DEBUG; private static final boolean DEBUG = MainActivity.DEBUG;
private final int maxVolume; private final int maxVolume;
public PlayerGestureListener(final VideoPlayerImpl playerImpl, final MainPlayer service) { public PlayerGestureListener(final Player player, final MainPlayer service) {
super(playerImpl, service); super(player, service);
maxVolume = playerImpl.getAudioReactor().getMaxVolume(); maxVolume = player.getAudioReactor().getMaxVolume();
} }
@Override @Override
@ -48,46 +48,44 @@ public class PlayerGestureListener
@NotNull final DisplayPortion portion) { @NotNull final DisplayPortion portion) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onDoubleTap called with playerType = [" Log.d(TAG, "onDoubleTap called with playerType = ["
+ playerImpl.getPlayerType() + "], portion = [" + player.getPlayerType() + "], portion = [" + portion + "]");
+ portion + "]");
} }
if (playerImpl.isSomePopupMenuVisible()) { if (player.isSomePopupMenuVisible()) {
playerImpl.hideControls(0, 0); player.hideControls(0, 0);
} }
if (portion == DisplayPortion.LEFT) { if (portion == DisplayPortion.LEFT) {
playerImpl.onFastRewind(); player.fastRewind();
} else if (portion == DisplayPortion.MIDDLE) { } else if (portion == DisplayPortion.MIDDLE) {
playerImpl.onPlayPause(); player.playPause();
} else if (portion == DisplayPortion.RIGHT) { } else if (portion == DisplayPortion.RIGHT) {
playerImpl.onFastForward(); player.fastForward();
} }
} }
@Override @Override
public void onSingleTap(@NotNull final MainPlayer.PlayerType playerType) { public void onSingleTap(@NotNull final MainPlayer.PlayerType playerType) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onSingleTap called with playerType = [" Log.d(TAG, "onSingleTap called with playerType = [" + player.getPlayerType() + "]");
+ playerImpl.getPlayerType() + "]");
} }
if (playerType == MainPlayer.PlayerType.POPUP) { if (playerType == MainPlayer.PlayerType.POPUP) {
if (playerImpl.isControlsVisible()) { if (player.isControlsVisible()) {
playerImpl.hideControls(100, 100); player.hideControls(100, 100);
} else { } else {
playerImpl.getPlayPauseButton().requestFocus(); player.getPlayPauseButton().requestFocus();
playerImpl.showControlsThenHide(); player.showControlsThenHide();
} }
} else /* playerType == MainPlayer.PlayerType.VIDEO */ { } else /* playerType == MainPlayer.PlayerType.VIDEO */ {
if (playerImpl.isControlsVisible()) { if (player.isControlsVisible()) {
playerImpl.hideControls(150, 0); player.hideControls(150, 0);
} else { } else {
if (playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) { if (player.getCurrentState() == Player.STATE_COMPLETED) {
playerImpl.showControls(0); player.showControls(0);
} else { } else {
playerImpl.showControlsThenHide(); player.showControlsThenHide();
} }
} }
} }
@ -101,8 +99,7 @@ public class PlayerGestureListener
final float distanceX, final float distanceY) { final float distanceX, final float distanceY) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onScroll called with playerType = [" Log.d(TAG, "onScroll called with playerType = ["
+ playerImpl.getPlayerType() + "], portion = [" + player.getPlayerType() + "], portion = [" + portion + "]");
+ portion + "]");
} }
if (playerType == MainPlayer.PlayerType.VIDEO) { if (playerType == MainPlayer.PlayerType.VIDEO) {
final boolean isBrightnessGestureEnabled = final boolean isBrightnessGestureEnabled =
@ -123,8 +120,8 @@ public class PlayerGestureListener
} }
} else /* MainPlayer.PlayerType.POPUP */ { } else /* MainPlayer.PlayerType.POPUP */ {
final View closingOverlayView = playerImpl.getClosingOverlay(); final View closingOverlayView = player.getClosingOverlayView();
if (playerImpl.isInsideClosingRadius(movingEvent)) { if (player.isInsideClosingRadius(movingEvent)) {
if (closingOverlayView.getVisibility() == View.GONE) { if (closingOverlayView.getVisibility() == View.GONE) {
animateView(closingOverlayView, true, 250); animateView(closingOverlayView, true, 250);
} }
@ -137,17 +134,17 @@ public class PlayerGestureListener
} }
private void onScrollMainVolume(final float distanceX, final float distanceY) { private void onScrollMainVolume(final float distanceX, final float distanceY) {
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY); player.getVolumeProgressBar().incrementProgressBy((int) distanceY);
final float currentProgressPercent = (float) playerImpl final float currentProgressPercent = (float) player
.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength(); .getVolumeProgressBar().getProgress() / player.getMaxGestureLength();
final int currentVolume = (int) (maxVolume * currentProgressPercent); final int currentVolume = (int) (maxVolume * currentProgressPercent);
playerImpl.getAudioReactor().setVolume(currentVolume); player.getAudioReactor().setVolume(currentVolume);
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume); Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume);
} }
playerImpl.getVolumeImageView().setImageDrawable( player.getVolumeImageView().setImageDrawable(
AppCompatResources.getDrawable(service, currentProgressPercent <= 0 AppCompatResources.getDrawable(service, currentProgressPercent <= 0
? R.drawable.ic_volume_off_white_24dp ? R.drawable.ic_volume_off_white_24dp
: currentProgressPercent < 0.25 ? R.drawable.ic_volume_mute_white_24dp : currentProgressPercent < 0.25 ? R.drawable.ic_volume_mute_white_24dp
@ -155,23 +152,23 @@ public class PlayerGestureListener
: R.drawable.ic_volume_up_white_24dp) : R.drawable.ic_volume_up_white_24dp)
); );
if (playerImpl.getVolumeRelativeLayout().getVisibility() != View.VISIBLE) { if (player.getVolumeRelativeLayout().getVisibility() != View.VISIBLE) {
animateView(playerImpl.getVolumeRelativeLayout(), SCALE_AND_ALPHA, true, 200); animateView(player.getVolumeRelativeLayout(), SCALE_AND_ALPHA, true, 200);
} }
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) { if (player.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE); player.getBrightnessRelativeLayout().setVisibility(View.GONE);
} }
} }
private void onScrollMainBrightness(final float distanceX, final float distanceY) { private void onScrollMainBrightness(final float distanceX, final float distanceY) {
final Activity parent = playerImpl.getParentActivity(); final Activity parent = player.getParentActivity();
if (parent == null) { if (parent == null) {
return; return;
} }
final Window window = parent.getWindow(); final Window window = parent.getWindow();
final WindowManager.LayoutParams layoutParams = window.getAttributes(); final WindowManager.LayoutParams layoutParams = window.getAttributes();
final ProgressBar bar = playerImpl.getBrightnessProgressBar(); final ProgressBar bar = player.getBrightnessProgressBar();
final float oldBrightness = layoutParams.screenBrightness; final float oldBrightness = layoutParams.screenBrightness;
bar.setProgress((int) (bar.getMax() * Math.max(0, Math.min(1, oldBrightness)))); bar.setProgress((int) (bar.getMax() * Math.max(0, Math.min(1, oldBrightness))));
bar.incrementProgressBy((int) distanceY); bar.incrementProgressBy((int) distanceY);
@ -188,7 +185,7 @@ public class PlayerGestureListener
+ "currentBrightness = " + currentProgressPercent); + "currentBrightness = " + currentProgressPercent);
} }
playerImpl.getBrightnessImageView().setImageDrawable( player.getBrightnessImageView().setImageDrawable(
AppCompatResources.getDrawable(service, AppCompatResources.getDrawable(service,
currentProgressPercent < 0.25 currentProgressPercent < 0.25
? R.drawable.ic_brightness_low_white_24dp ? R.drawable.ic_brightness_low_white_24dp
@ -197,11 +194,11 @@ public class PlayerGestureListener
: R.drawable.ic_brightness_high_white_24dp) : R.drawable.ic_brightness_high_white_24dp)
); );
if (playerImpl.getBrightnessRelativeLayout().getVisibility() != View.VISIBLE) { if (player.getBrightnessRelativeLayout().getVisibility() != View.VISIBLE) {
animateView(playerImpl.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, true, 200); animateView(player.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, true, 200);
} }
if (playerImpl.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) { if (player.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
playerImpl.getVolumeRelativeLayout().setVisibility(View.GONE); player.getVolumeRelativeLayout().setVisibility(View.GONE);
} }
} }
@ -210,40 +207,40 @@ public class PlayerGestureListener
@NotNull final MotionEvent event) { @NotNull final MotionEvent event) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onScrollEnd called with playerType = [" Log.d(TAG, "onScrollEnd called with playerType = ["
+ playerImpl.getPlayerType() + "]"); + player.getPlayerType() + "]");
} }
if (playerType == MainPlayer.PlayerType.VIDEO) { if (playerType == MainPlayer.PlayerType.VIDEO) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onScrollEnd() called"); Log.d(TAG, "onScrollEnd() called");
} }
if (playerImpl.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) { if (player.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
animateView(playerImpl.getVolumeRelativeLayout(), SCALE_AND_ALPHA, animateView(player.getVolumeRelativeLayout(), SCALE_AND_ALPHA,
false, 200, 200); false, 200, 200);
} }
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) { if (player.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
animateView(playerImpl.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, animateView(player.getBrightnessRelativeLayout(), SCALE_AND_ALPHA,
false, 200, 200); false, 200, 200);
} }
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) { if (player.isControlsVisible() && player.getCurrentState() == STATE_PLAYING) {
playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); player.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
} }
} else { } else {
if (playerImpl == null) { if (player == null) {
return; return;
} }
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) { if (player.isControlsVisible() && player.getCurrentState() == STATE_PLAYING) {
playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); player.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
} }
if (playerImpl.isInsideClosingRadius(event)) { if (player.isInsideClosingRadius(event)) {
playerImpl.closePopup(); player.closePopup();
} else { } else {
animateView(playerImpl.getClosingOverlay(), false, 0); animateView(player.getClosingOverlayView(), false, 0);
if (!playerImpl.isPopupClosing) { if (!player.isPopupClosing()) {
animateView(playerImpl.getCloseButton(), false, 200); animateView(player.getCloseOverlayButton(), false, 200);
} }
} }
} }
@ -254,12 +251,12 @@ public class PlayerGestureListener
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onPopupResizingStart called"); Log.d(TAG, "onPopupResizingStart called");
} }
playerImpl.showAndAnimateControl(-1, true); player.showAndAnimateControl(-1, true);
playerImpl.getLoadingPanel().setVisibility(View.GONE); player.getLoadingPanel().setVisibility(View.GONE);
playerImpl.hideControls(0, 0); player.hideControls(0, 0);
animateView(playerImpl.getCurrentDisplaySeek(), false, 0, 0); animateView(player.getCurrentDisplaySeek(), false, 0, 0);
animateView(playerImpl.getResizingIndicator(), true, 200, 0); animateView(player.getResizingIndicator(), true, 200, 0);
} }
@Override @Override
@ -267,7 +264,7 @@ public class PlayerGestureListener
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onPopupResizingEnd called"); Log.d(TAG, "onPopupResizingEnd called");
} }
animateView(playerImpl.getResizingIndicator(), false, 100, 0); animateView(player.getResizingIndicator(), false, 100, 0);
} }
} }

View file

@ -1,10 +1,10 @@
package org.schabi.newpipe.player.event; package org.schabi.newpipe.player.event;
import org.schabi.newpipe.player.MainPlayer; import org.schabi.newpipe.player.MainPlayer;
import org.schabi.newpipe.player.VideoPlayerImpl; import org.schabi.newpipe.player.Player;
public interface PlayerServiceExtendedEventListener extends PlayerServiceEventListener { public interface PlayerServiceExtendedEventListener extends PlayerServiceEventListener {
void onServiceConnected(VideoPlayerImpl player, void onServiceConnected(Player player,
MainPlayer playerService, MainPlayer playerService,
boolean playAfterConnect); boolean playAfterConnect);
void onServiceDisconnected(); void onServiceDisconnected();

View file

@ -18,7 +18,7 @@ import androidx.fragment.app.DialogFragment;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.util.SliderStrategy; import org.schabi.newpipe.util.SliderStrategy;
import static org.schabi.newpipe.player.BasePlayer.DEBUG; import static org.schabi.newpipe.player.Player.DEBUG;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
public class PlaybackParameterDialog extends DialogFragment { public class PlaybackParameterDialog extends DialogFragment {

View file

@ -1,8 +1,15 @@
package org.schabi.newpipe.player.helper; package org.schabi.newpipe.player.helper;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.CaptioningManager; import android.view.accessibility.CaptioningManager;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
@ -11,11 +18,14 @@ import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player.RepeatMode;
import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.text.CaptionStyleCompat; import com.google.android.exoplayer2.text.CaptionStyleCompat;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
@ -27,6 +37,8 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.SubtitlesStream; import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.extractor.utils.Utils;
import org.schabi.newpipe.player.MainPlayer;
import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
@ -41,13 +53,16 @@ import java.util.Formatter;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FILL; import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT; import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM; import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.lang.annotation.RetentionPolicy.SOURCE;
import static org.schabi.newpipe.player.Player.IDLE_WINDOW_FLAGS;
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_ALWAYS;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER; import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI; import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI;
@ -71,6 +86,15 @@ public final class PlayerHelper {
int AUTOPLAY_TYPE_NEVER = 2; int AUTOPLAY_TYPE_NEVER = 2;
} }
@Retention(SOURCE)
@IntDef({MINIMIZE_ON_EXIT_MODE_NONE, MINIMIZE_ON_EXIT_MODE_BACKGROUND,
MINIMIZE_ON_EXIT_MODE_POPUP})
public @interface MinimizeMode {
int MINIMIZE_ON_EXIT_MODE_NONE = 0;
int MINIMIZE_ON_EXIT_MODE_BACKGROUND = 1;
int MINIMIZE_ON_EXIT_MODE_POPUP = 2;
}
private PlayerHelper() { } private PlayerHelper() { }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -121,14 +145,16 @@ public final class PlayerHelper {
@NonNull @NonNull
public static String resizeTypeOf(@NonNull final Context context, public static String resizeTypeOf(@NonNull final Context context,
@AspectRatioFrameLayout.ResizeMode final int resizeMode) { @ResizeMode final int resizeMode) {
switch (resizeMode) { switch (resizeMode) {
case RESIZE_MODE_FIT: case AspectRatioFrameLayout.RESIZE_MODE_FIT:
return context.getResources().getString(R.string.resize_fit); return context.getResources().getString(R.string.resize_fit);
case RESIZE_MODE_FILL: case AspectRatioFrameLayout.RESIZE_MODE_FILL:
return context.getResources().getString(R.string.resize_fill); return context.getResources().getString(R.string.resize_fill);
case RESIZE_MODE_ZOOM: case AspectRatioFrameLayout.RESIZE_MODE_ZOOM:
return context.getResources().getString(R.string.resize_zoom); return context.getResources().getString(R.string.resize_zoom);
case AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT:
case AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH:
default: default:
throw new IllegalArgumentException("Unrecognized resize mode: " + resizeMode); throw new IllegalArgumentException("Unrecognized resize mode: " + resizeMode);
} }
@ -199,23 +225,23 @@ public final class PlayerHelper {
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) { public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
return isResumeAfterAudioFocusGain(context, false); return getPreferences(context)
.getBoolean(context.getString(R.string.resume_on_audio_focus_gain_key), false);
} }
public static boolean isVolumeGestureEnabled(@NonNull final Context context) { public static boolean isVolumeGestureEnabled(@NonNull final Context context) {
return isVolumeGestureEnabled(context, true); return getPreferences(context)
.getBoolean(context.getString(R.string.volume_gesture_control_key), true);
} }
public static boolean isBrightnessGestureEnabled(@NonNull final Context context) { public static boolean isBrightnessGestureEnabled(@NonNull final Context context) {
return isBrightnessGestureEnabled(context, true); return getPreferences(context)
} .getBoolean(context.getString(R.string.brightness_gesture_control_key), true);
public static boolean isRememberingPopupDimensions(@NonNull final Context context) {
return isRememberingPopupDimensions(context, true);
} }
public static boolean isAutoQueueEnabled(@NonNull final Context context) { public static boolean isAutoQueueEnabled(@NonNull final Context context) {
return isAutoQueueEnabled(context, false); return getPreferences(context)
.getBoolean(context.getString(R.string.auto_queue_key), false);
} }
public static boolean isClearingQueueConfirmationRequired(@NonNull final Context context) { public static boolean isClearingQueueConfirmationRequired(@NonNull final Context context) {
@ -229,7 +255,8 @@ public final class PlayerHelper {
final String popupAction = context.getString(R.string.minimize_on_exit_popup_key); final String popupAction = context.getString(R.string.minimize_on_exit_popup_key);
final String backgroundAction = context.getString(R.string.minimize_on_exit_background_key); final String backgroundAction = context.getString(R.string.minimize_on_exit_background_key);
final String action = getMinimizeOnExitAction(context, defaultAction); final String action = getPreferences(context)
.getString(context.getString(R.string.minimize_on_exit_key), defaultAction);
if (action.equals(popupAction)) { if (action.equals(popupAction)) {
return MINIMIZE_ON_EXIT_MODE_POPUP; return MINIMIZE_ON_EXIT_MODE_POPUP;
} else if (action.equals(backgroundAction)) { } else if (action.equals(backgroundAction)) {
@ -239,9 +266,23 @@ public final class PlayerHelper {
} }
} }
public static boolean isMinimizeOnExitToPopup(@NonNull final Context context) {
return getMinimizeOnExitAction(context) == MINIMIZE_ON_EXIT_MODE_POPUP;
}
public static boolean isMinimizeOnExitToBackground(@NonNull final Context context) {
return getMinimizeOnExitAction(context) == MINIMIZE_ON_EXIT_MODE_BACKGROUND;
}
public static boolean isMinimizeOnExitDisabled(@NonNull final Context context) {
return getMinimizeOnExitAction(context) == MINIMIZE_ON_EXIT_MODE_NONE;
}
@AutoplayType @AutoplayType
public static int getAutoplayType(@NonNull final Context context) { public static int getAutoplayType(@NonNull final Context context) {
final String type = getAutoplayType(context, context.getString(R.string.autoplay_wifi_key)); final String type = getPreferences(context).getString(
context.getString(R.string.autoplay_key),
context.getString(R.string.autoplay_wifi_key));
if (type.equals(context.getString(R.string.autoplay_always_key))) { if (type.equals(context.getString(R.string.autoplay_always_key))) {
return AUTOPLAY_TYPE_ALWAYS; return AUTOPLAY_TYPE_ALWAYS;
} else if (type.equals(context.getString(R.string.autoplay_never_key))) { } else if (type.equals(context.getString(R.string.autoplay_never_key))) {
@ -350,14 +391,32 @@ public final class PlayerHelper {
return captioningManager.getFontScale(); return captioningManager.getFontScale();
} }
/**
* @param context the Android context
* @return the screen brightness to use. A value less than 0 (the default) means to use the
* preferred screen brightness
*/
public static float getScreenBrightness(@NonNull final Context context) { public static float getScreenBrightness(@NonNull final Context context) {
//a value of less than 0, the default, means to use the preferred screen brightness final SharedPreferences sp = getPreferences(context);
return getScreenBrightness(context, -1); final long timestamp =
sp.getLong(context.getString(R.string.screen_brightness_timestamp_key), 0);
// Hypothesis: 4h covers a viewing block, e.g. evening.
// External lightning conditions will change in the next
// viewing block so we fall back to the default brightness
if ((System.currentTimeMillis() - timestamp) > TimeUnit.HOURS.toMillis(4)) {
return -1;
} else {
return sp.getFloat(context.getString(R.string.screen_brightness_key), -1);
}
} }
public static void setScreenBrightness(@NonNull final Context context, public static void setScreenBrightness(@NonNull final Context context,
final float setScreenBrightness) { final float screenBrightness) {
setScreenBrightness(context, setScreenBrightness, System.currentTimeMillis()); getPreferences(context).edit()
.putFloat(context.getString(R.string.screen_brightness_key), screenBrightness)
.putLong(context.getString(R.string.screen_brightness_timestamp_key),
System.currentTimeMillis())
.apply();
} }
public static boolean globalScreenOrientationLocked(final Context context) { public static boolean globalScreenOrientationLocked(final Context context) {
@ -376,75 +435,11 @@ public final class PlayerHelper {
return PreferenceManager.getDefaultSharedPreferences(context); return PreferenceManager.getDefaultSharedPreferences(context);
} }
private static boolean isResumeAfterAudioFocusGain(@NonNull final Context context,
final boolean b) {
return getPreferences(context)
.getBoolean(context.getString(R.string.resume_on_audio_focus_gain_key), b);
}
private static boolean isVolumeGestureEnabled(@NonNull final Context context,
final boolean b) {
return getPreferences(context)
.getBoolean(context.getString(R.string.volume_gesture_control_key), b);
}
private static boolean isBrightnessGestureEnabled(@NonNull final Context context,
final boolean b) {
return getPreferences(context)
.getBoolean(context.getString(R.string.brightness_gesture_control_key), b);
}
private static boolean isRememberingPopupDimensions(@NonNull final Context context,
final boolean b) {
return getPreferences(context)
.getBoolean(context.getString(R.string.popup_remember_size_pos_key), b);
}
private static boolean isUsingInexactSeek(@NonNull final Context context) { private static boolean isUsingInexactSeek(@NonNull final Context context) {
return getPreferences(context) return getPreferences(context)
.getBoolean(context.getString(R.string.use_inexact_seek_key), false); .getBoolean(context.getString(R.string.use_inexact_seek_key), false);
} }
private static boolean isAutoQueueEnabled(@NonNull final Context context, final boolean b) {
return getPreferences(context).getBoolean(context.getString(R.string.auto_queue_key), b);
}
private static void setScreenBrightness(@NonNull final Context context,
final float screenBrightness, final long timestamp) {
final SharedPreferences.Editor editor = getPreferences(context).edit();
editor.putFloat(context.getString(R.string.screen_brightness_key), screenBrightness);
editor.putLong(context.getString(R.string.screen_brightness_timestamp_key), timestamp);
editor.apply();
}
private static float getScreenBrightness(@NonNull final Context context,
final float screenBrightness) {
final SharedPreferences sp = getPreferences(context);
final long timestamp = sp
.getLong(context.getString(R.string.screen_brightness_timestamp_key), 0);
// Hypothesis: 4h covers a viewing block, e.g. evening.
// External lightning conditions will change in the next
// viewing block so we fall back to the default brightness
if ((System.currentTimeMillis() - timestamp) > TimeUnit.HOURS.toMillis(4)) {
return screenBrightness;
} else {
return sp
.getFloat(context.getString(R.string.screen_brightness_key), screenBrightness);
}
}
private static String getMinimizeOnExitAction(@NonNull final Context context,
final String key) {
return getPreferences(context)
.getString(context.getString(R.string.minimize_on_exit_key), key);
}
private static String getAutoplayType(@NonNull final Context context,
final String key) {
return getPreferences(context).getString(context.getString(R.string.autoplay_key),
key);
}
private static SinglePlayQueue getAutoQueuedSinglePlayQueue( private static SinglePlayQueue getAutoQueuedSinglePlayQueue(
final StreamInfoItem streamInfoItem) { final StreamInfoItem streamInfoItem) {
final SinglePlayQueue singlePlayQueue = new SinglePlayQueue(streamInfoItem); final SinglePlayQueue singlePlayQueue = new SinglePlayQueue(streamInfoItem);
@ -452,12 +447,168 @@ public final class PlayerHelper {
return singlePlayQueue; return singlePlayQueue;
} }
@Retention(SOURCE)
@IntDef({MINIMIZE_ON_EXIT_MODE_NONE, MINIMIZE_ON_EXIT_MODE_BACKGROUND, ////////////////////////////////////////////////////////////////////////////
MINIMIZE_ON_EXIT_MODE_POPUP}) // Utils used by player
public @interface MinimizeMode { ////////////////////////////////////////////////////////////////////////////
int MINIMIZE_ON_EXIT_MODE_NONE = 0;
int MINIMIZE_ON_EXIT_MODE_BACKGROUND = 1; public static MainPlayer.PlayerType retrievePlayerTypeFromIntent(final Intent intent) {
int MINIMIZE_ON_EXIT_MODE_POPUP = 2; // If you want to open popup from the app just include Constants.POPUP_ONLY into an extra
return MainPlayer.PlayerType.values()[
intent.getIntExtra(PLAYER_TYPE, MainPlayer.PlayerType.VIDEO.ordinal())];
}
public static boolean isPlaybackResumeEnabled(final Player player) {
return player.getPrefs().getBoolean(
player.getContext().getString(R.string.enable_watch_history_key), true)
&& player.getPrefs().getBoolean(
player.getContext().getString(R.string.enable_playback_resume_key), true);
}
@RepeatMode
public static int nextRepeatMode(@RepeatMode final int repeatMode) {
switch (repeatMode) {
case REPEAT_MODE_OFF:
return REPEAT_MODE_ONE;
case REPEAT_MODE_ONE:
return REPEAT_MODE_ALL;
case REPEAT_MODE_ALL: default:
return REPEAT_MODE_OFF;
}
}
@ResizeMode
public static int retrieveResizeModeFromPrefs(final Player player) {
return player.getPrefs().getInt(player.getContext().getString(R.string.last_resize_mode),
AspectRatioFrameLayout.RESIZE_MODE_FIT);
}
@SuppressLint("SwitchIntDef") // only fit, fill and zoom are supported by NewPipe
@ResizeMode
public static int nextResizeModeAndSaveToPrefs(final Player player,
@ResizeMode final int resizeMode) {
final int newResizeMode;
switch (resizeMode) {
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL;
break;
case AspectRatioFrameLayout.RESIZE_MODE_FILL:
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
break;
case AspectRatioFrameLayout.RESIZE_MODE_ZOOM:
default:
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
break;
}
player.getPrefs().edit().putInt(
player.getContext().getString(R.string.last_resize_mode), resizeMode).apply();
return newResizeMode;
}
public static PlaybackParameters retrievePlaybackParametersFromPrefs(final Player player) {
final float speed = player.getPrefs().getFloat(player.getContext().getString(
R.string.playback_speed_key), player.getPlaybackSpeed());
final float pitch = player.getPrefs().getFloat(player.getContext().getString(
R.string.playback_pitch_key), player.getPlaybackPitch());
final boolean skipSilence = player.getPrefs().getBoolean(player.getContext().getString(
R.string.playback_skip_silence_key), player.getPlaybackSkipSilence());
return new PlaybackParameters(speed, pitch, skipSilence);
}
public static void savePlaybackParametersToPrefs(final Player player,
final float speed,
final float pitch,
final boolean skipSilence) {
player.getPrefs().edit()
.putFloat(player.getContext().getString(R.string.playback_speed_key), speed)
.putFloat(player.getContext().getString(R.string.playback_pitch_key), pitch)
.putBoolean(player.getContext().getString(R.string.playback_skip_silence_key),
skipSilence)
.apply();
}
/**
* @param player {@code screenWidth} and {@code screenHeight} must have been initialized
* @return the popup starting layout params
*/
@SuppressLint("RtlHardcoded")
public static WindowManager.LayoutParams retrievePopupLayoutParamsFromPrefs(
final Player player) {
final boolean popupRememberSizeAndPos = player.getPrefs().getBoolean(
player.getContext().getString(R.string.popup_remember_size_pos_key), true);
final float defaultSize =
player.getContext().getResources().getDimension(R.dimen.popup_default_width);
final float popupWidth = popupRememberSizeAndPos
? player.getPrefs().getFloat(player.getContext().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) (player.getScreenWidth() / 2f - popupWidth / 2f);
final int centerY = (int) (player.getScreenHeight() / 2f - popupHeight / 2f);
popupLayoutParams.x = popupRememberSizeAndPos
? player.getPrefs().getInt(player.getContext().getString(
R.string.popup_saved_x_key), centerX) : centerX;
popupLayoutParams.y = popupRememberSizeAndPos
? player.getPrefs().getInt(player.getContext().getString(
R.string.popup_saved_y_key), centerY) : centerY;
return popupLayoutParams;
}
public static void savePopupPositionAndSizeToPrefs(final Player player) {
if (player.getPopupLayoutParams() != null) {
player.getPrefs().edit()
.putFloat(player.getContext().getString(R.string.popup_saved_width_key),
player.getPopupLayoutParams().width)
.putInt(player.getContext().getString(R.string.popup_saved_x_key),
player.getPopupLayoutParams().x)
.putInt(player.getContext().getString(R.string.popup_saved_y_key),
player.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);
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),
player.getContext().getString(R.string.seek_duration_default_value))));
} }
} }

View file

@ -16,7 +16,7 @@ import org.schabi.newpipe.App;
import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.MainPlayer; import org.schabi.newpipe.player.MainPlayer;
import org.schabi.newpipe.player.VideoPlayerImpl; import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.event.PlayerServiceEventListener; import org.schabi.newpipe.player.event.PlayerServiceEventListener;
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener; import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener;
import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
@ -33,7 +33,7 @@ public final class PlayerHolder {
private static ServiceConnection serviceConnection; private static ServiceConnection serviceConnection;
public static boolean bound; public static boolean bound;
private static MainPlayer playerService; private static MainPlayer playerService;
private static VideoPlayerImpl player; private static Player player;
/** /**
* Returns the current {@link MainPlayer.PlayerType} of the {@link MainPlayer} service, * Returns the current {@link MainPlayer.PlayerType} of the {@link MainPlayer} service,

View file

@ -3,11 +3,11 @@ package org.schabi.newpipe.player.mediasession;
import android.support.v4.media.MediaDescriptionCompat; import android.support.v4.media.MediaDescriptionCompat;
public interface MediaSessionCallback { public interface MediaSessionCallback {
void onSkipToPrevious(); void playPrevious();
void onSkipToNext(); void playNext();
void onSkipToIndex(int index); void playItemAtIndex(int index);
int getCurrentPlayingIndex(); int getCurrentPlayingIndex();
@ -15,7 +15,7 @@ public interface MediaSessionCallback {
MediaDescriptionCompat getQueueMetadata(int index); MediaDescriptionCompat getQueueMetadata(int index);
void onPlay(); void play();
void onPause(); void pause();
} }

View file

@ -65,18 +65,18 @@ public class PlayQueueNavigator implements MediaSessionConnector.QueueNavigator
@Override @Override
public void onSkipToPrevious(final Player player, final ControlDispatcher controlDispatcher) { public void onSkipToPrevious(final Player player, final ControlDispatcher controlDispatcher) {
callback.onSkipToPrevious(); callback.playPrevious();
} }
@Override @Override
public void onSkipToQueueItem(final Player player, final ControlDispatcher controlDispatcher, public void onSkipToQueueItem(final Player player, final ControlDispatcher controlDispatcher,
final long id) { final long id) {
callback.onSkipToIndex((int) id); callback.playItemAtIndex((int) id);
} }
@Override @Override
public void onSkipToNext(final Player player, final ControlDispatcher controlDispatcher) { public void onSkipToNext(final Player player, final ControlDispatcher controlDispatcher) {
callback.onSkipToNext(); callback.playNext();
} }
private void publishFloatingQueueWindow() { private void publishFloatingQueueWindow() {

View file

@ -14,9 +14,9 @@ public class PlayQueuePlaybackController extends DefaultControlDispatcher {
@Override @Override
public boolean dispatchSetPlayWhenReady(final Player player, final boolean playWhenReady) { public boolean dispatchSetPlayWhenReady(final Player player, final boolean playWhenReady) {
if (playWhenReady) { if (playWhenReady) {
callback.onPlay(); callback.play();
} else { } else {
callback.onPause(); callback.pause();
} }
return true; return true;
} }

View file

@ -5,33 +5,33 @@ import android.os.Bundle;
import android.support.v4.media.MediaDescriptionCompat; import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.MediaMetadataCompat;
import org.schabi.newpipe.player.BasePlayer; import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.mediasession.MediaSessionCallback; import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
public class BasePlayerMediaSession implements MediaSessionCallback { public class PlayerMediaSession implements MediaSessionCallback {
private final BasePlayer player; private final Player player;
public BasePlayerMediaSession(final BasePlayer player) { public PlayerMediaSession(final Player player) {
this.player = player; this.player = player;
} }
@Override @Override
public void onSkipToPrevious() { public void playPrevious() {
player.onPlayPrevious(); player.playPrevious();
} }
@Override @Override
public void onSkipToNext() { public void playNext() {
player.onPlayNext(); player.playNext();
} }
@Override @Override
public void onSkipToIndex(final int index) { public void playItemAtIndex(final int index) {
if (player.getPlayQueue() == null) { if (player.getPlayQueue() == null) {
return; return;
} }
player.onSelected(player.getPlayQueue().getItem(index)); player.selectQueueItem(player.getPlayQueue().getItem(index));
} }
@Override @Override
@ -52,11 +52,14 @@ public class BasePlayerMediaSession implements MediaSessionCallback {
@Override @Override
public MediaDescriptionCompat getQueueMetadata(final int index) { public MediaDescriptionCompat getQueueMetadata(final int index) {
if (player.getPlayQueue() == null || player.getPlayQueue().getItem(index) == null) { if (player.getPlayQueue() == null) {
return null;
}
final PlayQueueItem item = player.getPlayQueue().getItem(index);
if (item == null) {
return null; return null;
} }
final PlayQueueItem item = player.getPlayQueue().getItem(index);
final MediaDescriptionCompat.Builder descriptionBuilder final MediaDescriptionCompat.Builder descriptionBuilder
= new MediaDescriptionCompat.Builder() = new MediaDescriptionCompat.Builder()
.setMediaId(String.valueOf(index)) .setMediaId(String.valueOf(index))
@ -83,12 +86,12 @@ public class BasePlayerMediaSession implements MediaSessionCallback {
} }
@Override @Override
public void onPlay() { public void play() {
player.onPlay(); player.play();
} }
@Override @Override
public void onPause() { public void pause() {
player.onPause(); player.pause();
} }
} }

View file

@ -351,4 +351,19 @@ public final class Localization {
private static double round(final double value, final int places) { private static double round(final double value, final int places) {
return new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue(); return new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue();
} }
/**
* Workaround to match normalized captions like english to English or deutsch to Deutsch.
* @param list the list to search into
* @param toFind the string to look for
* @return whether the string was found or not
*/
public static boolean containsCaseInsensitive(final List<String> list, final String toFind) {
for (final String i : list) {
if (i.equalsIgnoreCase(toFind)) {
return true;
}
}
return false;
}
} }

View file

@ -46,10 +46,9 @@ import org.schabi.newpipe.local.history.StatisticsPlaylistFragment;
import org.schabi.newpipe.local.playlist.LocalPlaylistFragment; import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
import org.schabi.newpipe.local.subscription.SubscriptionFragment; import org.schabi.newpipe.local.subscription.SubscriptionFragment;
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment; import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
import org.schabi.newpipe.player.BackgroundPlayerActivity; import org.schabi.newpipe.player.PlayQueueActivity;
import org.schabi.newpipe.player.BasePlayer; import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.MainPlayer; import org.schabi.newpipe.player.MainPlayer;
import org.schabi.newpipe.player.VideoPlayer;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.helper.PlayerHolder; import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
@ -78,11 +77,11 @@ public final class NavigationHelper {
if (playQueue != null) { if (playQueue != null) {
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class); final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
if (cacheKey != null) { if (cacheKey != null) {
intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey); intent.putExtra(Player.PLAY_QUEUE_KEY, cacheKey);
} }
} }
intent.putExtra(VideoPlayer.RESUME_PLAYBACK, resumePlayback); intent.putExtra(Player.RESUME_PLAYBACK, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_VIDEO); intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.VIDEO.ordinal());
return intent; return intent;
} }
@ -94,7 +93,7 @@ public final class NavigationHelper {
final boolean resumePlayback, final boolean resumePlayback,
final boolean playWhenReady) { final boolean playWhenReady) {
return getPlayerIntent(context, targetClazz, playQueue, resumePlayback) return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
.putExtra(BasePlayer.PLAY_WHEN_READY, playWhenReady); .putExtra(Player.PLAY_WHEN_READY, playWhenReady);
} }
@NonNull @NonNull
@ -104,8 +103,8 @@ public final class NavigationHelper {
final boolean selectOnAppend, final boolean selectOnAppend,
final boolean resumePlayback) { final boolean resumePlayback) {
return getPlayerIntent(context, targetClazz, playQueue, resumePlayback) return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
.putExtra(BasePlayer.APPEND_ONLY, true) .putExtra(Player.APPEND_ONLY, true)
.putExtra(BasePlayer.SELECT_ON_APPEND, selectOnAppend); .putExtra(Player.SELECT_ON_APPEND, selectOnAppend);
} }
public static void playOnMainPlayer(final AppCompatActivity activity, public static void playOnMainPlayer(final AppCompatActivity activity,
@ -135,7 +134,7 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback); final Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_POPUP); intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.POPUP.ordinal());
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} }
@ -145,7 +144,7 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT) Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT)
.show(); .show();
final Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback); final Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_AUDIO); intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.AUDIO.ordinal());
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} }
@ -162,7 +161,7 @@ public final class NavigationHelper {
final Intent intent = getPlayerEnqueueIntent( final Intent intent = getPlayerEnqueueIntent(
context, MainPlayer.class, queue, selectOnAppend, resumePlayback); context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_VIDEO); intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.VIDEO.ordinal());
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} }
@ -182,7 +181,7 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerEnqueueIntent( final Intent intent = getPlayerEnqueueIntent(
context, MainPlayer.class, queue, selectOnAppend, resumePlayback); context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_POPUP); intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.POPUP.ordinal());
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} }
@ -198,7 +197,7 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerEnqueueIntent( final Intent intent = getPlayerEnqueueIntent(
context, MainPlayer.class, queue, selectOnAppend, resumePlayback); context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_AUDIO); intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.AUDIO.ordinal());
ContextCompat.startForegroundService(context, intent); ContextCompat.startForegroundService(context, intent);
} }
@ -493,7 +492,7 @@ public final class NavigationHelper {
if (playQueue != null) { if (playQueue != null) {
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class); final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
if (cacheKey != null) { if (cacheKey != null) {
intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey); intent.putExtra(Player.PLAY_QUEUE_KEY, cacheKey);
} }
} }
context.startActivity(intent); context.startActivity(intent);
@ -531,7 +530,7 @@ public final class NavigationHelper {
} }
public static Intent getPlayQueueActivityIntent(final Context context) { public static Intent getPlayQueueActivityIntent(final Context context) {
final Intent intent = new Intent(context, BackgroundPlayerActivity.class); final Intent intent = new Intent(context, PlayQueueActivity.class);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} }

View file

@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context="org.schabi.newpipe.player.BackgroundPlayerActivity"> tools:context="org.schabi.newpipe.player.PlayQueueActivity">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar" android:id="@+id/appbar"

View file

@ -145,7 +145,7 @@
tools:text="The Video Artist LONG very LONG very Long" /> tools:text="The Video Artist LONG very LONG very Long" />
</LinearLayout> </LinearLayout>
<Button <TextView
android:id="@+id/qualityTextView" android:id="@+id/qualityTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="35dp" android:layout_height="35dp"
@ -154,13 +154,12 @@
android:gravity="center" android:gravity="center"
android:minWidth="0dp" android:minWidth="0dp"
android:padding="@dimen/player_main_buttons_padding" android:padding="@dimen/player_main_buttons_padding"
android:text="720p"
android:textAllCaps="false"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textStyle="bold" android:textStyle="bold"
tools:ignore="HardcodedText,RtlHardcoded" /> tools:ignore="HardcodedText,RtlHardcoded"
tools:text="720p" />
<Button <TextView
android:id="@+id/playbackSpeed" android:id="@+id/playbackSpeed"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="35dp" android:layout_height="35dp"
@ -169,7 +168,6 @@
android:gravity="center" android:gravity="center"
android:minWidth="0dp" android:minWidth="0dp"
android:padding="@dimen/player_main_buttons_padding" android:padding="@dimen/player_main_buttons_padding"
android:textAllCaps="false"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textStyle="bold" android:textStyle="bold"
tools:ignore="RtlHardcoded,RtlSymmetry" tools:ignore="RtlHardcoded,RtlSymmetry"
@ -216,7 +214,7 @@
tools:ignore="RtlHardcoded" tools:ignore="RtlHardcoded"
tools:visibility="visible"> tools:visibility="visible">
<Button <TextView
android:id="@+id/resizeTextView" android:id="@+id/resizeTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="35dp" android:layout_height="35dp"

View file

@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context="org.schabi.newpipe.player.BackgroundPlayerActivity"> tools:context="org.schabi.newpipe.player.PlayQueueActivity">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar" android:id="@+id/appbar"

View file

@ -156,11 +156,10 @@
android:gravity="center" android:gravity="center"
android:minWidth="0dp" android:minWidth="0dp"
android:padding="@dimen/player_main_buttons_padding" android:padding="@dimen/player_main_buttons_padding"
android:text="720p"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textStyle="bold" android:textStyle="bold"
android:visibility="visible" tools:ignore="HardcodedText,RtlHardcoded"
tools:ignore="HardcodedText,RtlHardcoded" /> tools:text="720p" />
<TextView <TextView
android:id="@+id/playbackSpeed" android:id="@+id/playbackSpeed"
@ -350,7 +349,7 @@
tools:text="1:06:29" /> tools:text="1:06:29" />
<androidx.appcompat.widget.AppCompatSeekBar <org.schabi.newpipe.views.FocusAwareSeekBar
android:id="@+id/playbackSeekBar" android:id="@+id/playbackSeekBar"
style="@style/Widget.AppCompat.SeekBar" style="@style/Widget.AppCompat.SeekBar"
android:layout_width="0dp" android:layout_width="0dp"

View file

@ -1,7 +1,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context=".player.BackgroundPlayerActivity"> tools:context=".player.PlayQueueActivity">
<item <item
android:id="@+id/action_append_playlist" android:id="@+id/action_append_playlist"

View file

@ -21,7 +21,6 @@
<string name="use_external_video_player_key" translatable="false">use_external_video_player</string> <string name="use_external_video_player_key" translatable="false">use_external_video_player</string>
<string name="use_external_audio_player_key" translatable="false">use_external_audio_player</string> <string name="use_external_audio_player_key" translatable="false">use_external_audio_player</string>
<string name="use_old_player_key" translatable="false">use_oldplayer</string>
<string name="volume_gesture_control_key" translatable="false">volume_gesture_control</string> <string name="volume_gesture_control_key" translatable="false">volume_gesture_control</string>
<string name="brightness_gesture_control_key" translatable="false">brightness_gesture_control</string> <string name="brightness_gesture_control_key" translatable="false">brightness_gesture_control</string>
@ -33,6 +32,10 @@
<string name="screen_brightness_timestamp_key" translatable="false">screen_brightness_timestamp_key</string> <string name="screen_brightness_timestamp_key" translatable="false">screen_brightness_timestamp_key</string>
<string name="clear_queue_confirmation_key" translatable="false">clear_queue_confirmation_key</string> <string name="clear_queue_confirmation_key" translatable="false">clear_queue_confirmation_key</string>
<string name="popup_saved_width_key" translatable="false">popup_saved_width</string>
<string name="popup_saved_x_key" translatable="false">popup_saved_x</string>
<string name="popup_saved_y_key" translatable="false">popup_saved_y</string>
<string name="seek_duration_key" translatable="false">seek_duration</string> <string name="seek_duration_key" translatable="false">seek_duration</string>
<string name="seek_duration_default_value" translatable="false">10000</string> <string name="seek_duration_default_value" translatable="false">10000</string>
<string-array name="seek_duration_description" translatable="false"> <string-array name="seek_duration_description" translatable="false">
@ -70,7 +73,6 @@
<item>@string/minimize_on_exit_popup_description</item> <item>@string/minimize_on_exit_popup_description</item>
</string-array> </string-array>
<string name="autoplay_key" translatable="false">autoplay_key</string> <string name="autoplay_key" translatable="false">autoplay_key</string>
<string name="autoplay_value" translatable="false">@string/autoplay_wifi_key</string> <string name="autoplay_value" translatable="false">@string/autoplay_wifi_key</string>
<string name="autoplay_always_key" translatable="false">autoplay_always_key</string> <string name="autoplay_always_key" translatable="false">autoplay_always_key</string>

View file

@ -25,7 +25,7 @@
lines="156,158"/> lines="156,158"/>
<suppress checks="FileLength" <suppress checks="FileLength"
files="VideoPlayerImpl.java"/> files="Player.java"/>
<suppress checks="FileLength" <suppress checks="FileLength"
files="VideoDetailFragment.java"/> files="VideoDetailFragment.java"/>