1
0
mirror of https://github.com/TeamNewPipe/NewPipe.git synced 2024-11-22 19:12:45 +01:00

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>
<activity
android:name=".player.BackgroundPlayerActivity"
android:name=".player.PlayQueueActivity"
android:label="@string/title_activity_play_queue"
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.detail.VideoDetailFragment;
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.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue;
@ -759,7 +759,7 @@ public class MainActivity extends AppCompatActivity {
switch (linkType) {
case STREAM:
final String intentCacheKey = intent.getStringExtra(
VideoPlayer.PLAY_QUEUE_KEY);
Player.PLAY_QUEUE_KEY);
final PlayQueue playQueue = intentCacheKey != null
? SerializedCache.getInstance()
.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.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
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.PlaylistCreationDialog;
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.VideoPlayerImpl;
import org.schabi.newpipe.player.event.OnKeyDownListener;
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener;
import org.schabi.newpipe.player.helper.PlayerHelper;
@ -255,14 +253,14 @@ public final class VideoDetailFragment
private ContentObserver settingsContentObserver;
private MainPlayer playerService;
private VideoPlayerImpl player;
private Player player;
/*//////////////////////////////////////////////////////////////////////////
// Service management
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onServiceConnected(final VideoPlayerImpl connectedPlayer,
public void onServiceConnected(final Player connectedPlayer,
final MainPlayer connectedPlayerService,
final boolean playAfterConnect) {
player = connectedPlayer;
@ -539,7 +537,7 @@ public final class VideoDetailFragment
break;
case R.id.overlay_play_pause_button:
if (playerIsNotStopped()) {
player.onPlayPause();
player.playPause();
player.hideControls(0, 0);
showSystemUi();
} else {
@ -805,7 +803,7 @@ public final class VideoDetailFragment
// If we are in fullscreen mode just exit from it via first back press
if (player != null && player.isFullscreen()) {
if (!DeviceUtils.isTablet(activity)) {
player.onPause();
player.pause();
}
restoreDefaultOrientation();
setAutoPlay(false);
@ -850,7 +848,7 @@ public final class VideoDetailFragment
final PlayQueueItem playQueueItem = item.getPlayQueue().getItem();
// 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) {
updateOverlayData(playQueueItem.getTitle(),
playQueueItem.getUploader(), playQueueItem.getThumbnailUrl());
@ -1569,7 +1567,7 @@ public final class VideoDetailFragment
showMetaInfoInTextView(info.getMetaInfo(), detailMetaInfoTextView, detailMetaInfoSeparator);
if (player == null || player.isPlayerStopped()) {
if (player == null || player.isStopped()) {
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
}
@ -1797,7 +1795,7 @@ public final class VideoDetailFragment
setOverlayPlayPauseImage(player != null && player.isPlaying());
switch (state) {
case BasePlayer.STATE_PLAYING:
case Player.STATE_PLAYING:
if (positionView.getAlpha() != 1.0f
&& player.getPlayQueue() != null
&& player.getPlayQueue().getItem() != null
@ -1814,7 +1812,7 @@ public final class VideoDetailFragment
final int duration,
final int bufferPercent) {
// 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;
}
@ -1891,10 +1889,8 @@ public final class VideoDetailFragment
if (fullscreen) {
hideSystemUiIfNeeded();
viewPager.setVisibility(View.GONE);
} else {
showSystemUi();
viewPager.setVisibility(View.VISIBLE);
}
if (relatedStreamsLayout != null) {
@ -2020,9 +2016,7 @@ public final class VideoDetailFragment
}
private boolean playerIsNotStopped() {
return player != null
&& player.getPlayer() != null
&& player.getPlayer().getPlaybackState() != Player.STATE_IDLE;
return player != null && !player.isStopped();
}
private void restoreDefaultBrightness() {
@ -2073,7 +2067,7 @@ public final class VideoDetailFragment
player.checkLandscape();
// Let's give a user time to look at video information page if video is not playing
if (globalScreenOrientationLocked(activity) && !player.isPlaying()) {
player.onPlay();
player.play();
}
}
@ -2287,7 +2281,7 @@ public final class VideoDetailFragment
// Re-enable clicks
setOverlayElementsClickable(true);
if (player != null) {
player.onQueueClosed();
player.closeQueue();
}
setOverlayLook(appBarLayout, behavior, 0);
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 {
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 final IBinder mBinder = new MainPlayer.LocalBinder();
@ -69,8 +69,6 @@ public final class MainPlayer extends Service {
= App.PACKAGE_NAME + ".player.MainPlayer.CLOSE";
static final String ACTION_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
= App.PACKAGE_NAME + ".player.MainPlayer.REPEAT";
static final String ACTION_PLAY_NEXT
@ -105,11 +103,10 @@ public final class MainPlayer extends Service {
private void createView() {
final PlayerBinding binding = PlayerBinding.inflate(LayoutInflater.from(this));
playerImpl = new VideoPlayerImpl(this);
playerImpl.setup(binding);
playerImpl.shouldUpdateOnProgress = true;
player = new Player(this);
player.setupFromView(binding);
NotificationUtil.getInstance().createNotificationAndStartForeground(playerImpl, this);
NotificationUtil.getInstance().createNotificationAndStartForeground(player, this);
}
@Override
@ -119,19 +116,19 @@ public final class MainPlayer extends Service {
+ "], flags = [" + flags + "], startId = [" + startId + "]");
}
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
return START_NOT_STICKY;
}
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
|| intent.getStringExtra(VideoPlayer.PLAY_QUEUE_KEY) != null) {
NotificationUtil.getInstance().createNotificationAndStartForeground(playerImpl, this);
|| intent.getStringExtra(Player.PLAY_QUEUE_KEY) != null) {
NotificationUtil.getInstance().createNotificationAndStartForeground(player, this);
}
playerImpl.handleIntent(intent);
if (playerImpl.mediaSessionManager != null) {
playerImpl.mediaSessionManager.handleMediaButtonIntent(intent);
player.handleIntent(intent);
if (player.getMediaSessionManager() != null) {
player.getMediaSessionManager().handleMediaButtonIntent(intent);
}
return START_NOT_STICKY;
}
@ -141,20 +138,20 @@ public final class MainPlayer extends Service {
Log.d(TAG, "stop() called");
}
if (playerImpl.getPlayer() != null) {
playerImpl.wasPlaying = playerImpl.getPlayer().getPlayWhenReady();
if (!player.exoPlayerIsNull()) {
player.saveWasPlaying();
// Releases wifi & cpu, disables keepScreenOn, etc.
if (!autoplayEnabled) {
playerImpl.onPause();
player.pause();
}
// We can't just pause the player here because it will make transition
// from one stream to a new stream not smooth
playerImpl.getPlayer().stop(false);
playerImpl.setRecovery();
player.smoothStopPlayer();
player.setRecovery();
// Android TV will handle back button in case controls will be visible
// (one more additional unneeded click while the player is hidden)
playerImpl.hideControls(0, 0);
playerImpl.onQueueClosed();
player.hideControls(0, 0);
player.closeQueue();
// Notification shows information about old stream but if a user selects
// a stream from backStack it's not actual anymore
// So we should hide the notification at all.
@ -168,7 +165,7 @@ public final class MainPlayer extends Service {
@Override
public void onTaskRemoved(final Intent rootIntent) {
super.onTaskRemoved(rootIntent);
if (!playerImpl.videoPlayerSelected()) {
if (!player.videoPlayerSelected()) {
return;
}
onDestroy();
@ -181,7 +178,23 @@ public final class MainPlayer extends Service {
if (DEBUG) {
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
@ -194,32 +207,6 @@ public final class MainPlayer extends Service {
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
//////////////////////////////////////////////////////////////////////////*/
@ -227,25 +214,25 @@ public final class MainPlayer extends Service {
boolean isLandscape() {
// DisplayMetrics from activity context knows about MultiWindow feature
// while DisplayMetrics from app context doesn't
final DisplayMetrics metrics = (playerImpl != null
&& playerImpl.getParentActivity() != null
? playerImpl.getParentActivity().getResources()
final DisplayMetrics metrics = (player != null
&& player.getParentActivity() != null
? player.getParentActivity().getResources()
: getResources()).getDisplayMetrics();
return metrics.heightPixels < metrics.widthPixels;
}
@Nullable
public View getView() {
if (playerImpl == null) {
if (player == null) {
return null;
}
return playerImpl.getRootView();
return player.getRootView();
}
public void removeViewFromParent() {
if (getView() != null && getView().getParent() != null) {
if (playerImpl.getParentActivity() != null) {
if (player.getParentActivity() != null) {
// This means view was added to fragment
final ViewGroup parent = (ViewGroup) getView().getParent();
parent.removeView(getView());
@ -263,8 +250,8 @@ public final class MainPlayer extends Service {
return MainPlayer.this;
}
public VideoPlayerImpl getPlayer() {
return MainPlayer.this.playerImpl;
public Player getPlayer() {
return MainPlayer.this.player;
}
}
}

View File

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

View File

@ -16,13 +16,11 @@ import android.widget.PopupMenu;
import android.widget.SeekBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import org.schabi.newpipe.R;
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.util.Localization.assureCorrectAppLanguage;
public abstract class ServicePlayerActivity extends AppCompatActivity
public final class PlayQueueActivity extends AppCompatActivity
implements PlayerEventListener, SeekBar.OnSeekBarChangeListener,
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 SMOOTH_SCROLL_MAXIMUM_DISTANCE = 80;
protected BasePlayer player;
protected Player player;
private boolean serviceBound;
private ServiceConnection serviceConnection;
private boolean seeking;
private boolean redraw;
////////////////////////////////////////////////////////////////////////////
// Views
@ -73,24 +73,6 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
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
////////////////////////////////////////////////////////////////////////////
@ -107,35 +89,32 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
setSupportActionBar(queueControlBinding.toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(getSupportActionTitle());
getSupportActionBar().setTitle(R.string.title_activity_play_queue);
}
serviceConnection = getServiceConnection();
bind();
}
@Override
protected void onResume() {
super.onResume();
if (redraw) {
ActivityCompat.recreate(this);
redraw = false;
}
}
@Override
public boolean onCreateOptionsMenu(final Menu m) {
this.menu = m;
getMenuInflater().inflate(R.menu.menu_play_queue, m);
getMenuInflater().inflate(getPlayerOptionMenuResource(), m);
getMenuInflater().inflate(R.menu.menu_play_queue_bg, m);
onMaybeMuteChanged();
onPlaybackParameterChanged(player.getPlaybackParameters());
return true;
}
// Allow to setup visibility of menuItems
@Override
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);
}
@ -167,14 +146,14 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
case R.id.action_switch_popup:
if (PermissionHelper.isPopupEnabled(this)) {
this.player.setRecovery();
NavigationHelper.playOnPopupPlayer(this, player.playQueue, true);
NavigationHelper.playOnPopupPlayer(this, player.getPlayQueue(), true);
} else {
PermissionHelper.showPopupEnablementToast(this);
}
return true;
case R.id.action_switch_background:
this.player.setRecovery();
NavigationHelper.playOnBackgroundPlayer(this, player.playQueue, true);
NavigationHelper.playOnBackgroundPlayer(this, player.getPlayQueue(), true);
return true;
}
return super.onOptionsItemSelected(item);
@ -191,7 +170,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
////////////////////////////////////////////////////////////////////////////
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) {
unbindService(serviceConnection);
}
@ -202,7 +182,9 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
if (serviceBound) {
unbindService(serviceConnection);
serviceBound = false;
stopPlayerListener();
if (player != null) {
player.removeActivityListener(this);
}
if (player != null && player.getPlayQueueAdapter() != null) {
player.getPlayQueueAdapter().unsetSelectedListener();
@ -221,12 +203,12 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
return new ServiceConnection() {
@Override
public void onServiceDisconnected(final ComponentName name) {
Log.d(getTag(), "Player service is disconnected");
Log.d(TAG, "Player service is disconnected");
}
@Override
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) {
player = ((PlayerServiceBinder) service).getPlayerInstance();
@ -235,12 +217,14 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
}
if (player == null || player.getPlayQueue() == null
|| player.getPlayQueueAdapter() == null || player.getPlayer() == null) {
|| player.getPlayQueueAdapter() == null || player.exoPlayerIsNull()) {
unbind();
finish();
} else {
buildComponents();
startPlayerListener();
if (player != null) {
player.setActivityListener(PlayQueueActivity.this);
}
}
}
};
@ -375,7 +359,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
@Override
public void selected(final PlayQueueItem item, final View view) {
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()) {
player.onRepeatClicked();
} else if (view.getId() == queueControlBinding.controlBackward.getId()) {
player.onPlayPrevious();
player.playPrevious();
} else if (view.getId() == queueControlBinding.controlFastRewind.getId()) {
player.onFastRewind();
player.fastRewind();
} else if (view.getId() == queueControlBinding.controlPlayPause.getId()) {
player.onPlayPause();
player.playPause();
} else if (view.getId() == queueControlBinding.controlFastForward.getId()) {
player.onFastForward();
player.fastForward();
} else if (view.getId() == queueControlBinding.controlForward.getId()) {
player.onPlayNext();
player.playNext();
} else if (view.getId() == queueControlBinding.controlShuffle.getId()) {
player.onShuffleClicked();
} else if (view.getId() == queueControlBinding.metadata.getId()) {
@ -463,7 +447,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
return;
}
PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), player.getPlaybackPitch(),
player.getPlaybackSkipSilence(), this).show(getSupportFragmentManager(), getTag());
player.getPlaybackSkipSilence(), this).show(getSupportFragmentManager(), TAG);
}
@Override
@ -517,10 +501,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
final PlaylistAppendDialog d = PlaylistAppendDialog.fromPlayQueueItems(playlist);
PlaylistAppendDialog.onPlaylistFound(getApplicationContext(),
() -> d.show(getSupportFragmentManager(), getTag()),
() -> PlaylistCreationDialog.newInstance(d)
.show(getSupportFragmentManager(), getTag()
));
() -> d.show(getSupportFragmentManager(), TAG),
() -> PlaylistCreationDialog.newInstance(d).show(getSupportFragmentManager(), TAG));
}
////////////////////////////////////////////////////////////////////////////
@ -616,15 +598,15 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
private void onStateChanged(final int state) {
switch (state) {
case BasePlayer.STATE_PAUSED:
case Player.STATE_PAUSED:
queueControlBinding.controlPlayPause
.setImageResource(R.drawable.ic_play_arrow_white_24dp);
break;
case BasePlayer.STATE_PLAYING:
case Player.STATE_PLAYING:
queueControlBinding.controlPlayPause
.setImageResource(R.drawable.ic_pause_white_24dp);
break;
case BasePlayer.STATE_COMPLETED:
case Player.STATE_COMPLETED:
queueControlBinding.controlPlayPause
.setImageResource(R.drawable.ic_replay_white_24dp);
break;
@ -633,9 +615,9 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
}
switch (state) {
case BasePlayer.STATE_PAUSED:
case BasePlayer.STATE_PLAYING:
case BasePlayer.STATE_COMPLETED:
case Player.STATE_PAUSED:
case Player.STATE_PLAYING:
case Player.STATE_COMPLETED:
queueControlBinding.controlPlayPause.setClickable(true);
queueControlBinding.controlPlayPause.setVisibility(View.VISIBLE);
queueControlBinding.controlProgressBar.setVisibility(View.GONE);
@ -650,15 +632,15 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
private void onPlayModeChanged(final int repeatMode, final boolean shuffled) {
switch (repeatMode) {
case Player.REPEAT_MODE_OFF:
case com.google.android.exoplayer2.Player.REPEAT_MODE_OFF:
queueControlBinding.controlRepeat
.setImageResource(R.drawable.exo_controls_repeat_off);
break;
case Player.REPEAT_MODE_ONE:
case com.google.android.exoplayer2.Player.REPEAT_MODE_ONE:
queueControlBinding.controlRepeat
.setImageResource(R.drawable.exo_controls_repeat_one);
break;
case Player.REPEAT_MODE_ALL:
case com.google.android.exoplayer2.Player.REPEAT_MODE_ALL:
queueControlBinding.controlRepeat
.setImageResource(R.drawable.exo_controls_repeat_all);
break;
@ -700,9 +682,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
// using rootView.getContext() because getApplicationContext() didn't work
final Context context = queueControlBinding.getRoot().getContext();
item.setIcon(ThemeHelper.resolveResourceIdFromAttr(context,
player.isMuted()
? R.attr.ic_volume_off
: R.attr.ic_volume_up));
player.isMuted() ? 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;
class PlayerServiceBinder extends Binder {
private final BasePlayer basePlayer;
private final Player player;
PlayerServiceBinder(@NonNull final BasePlayer basePlayer) {
this.basePlayer = basePlayer;
PlayerServiceBinder(@NonNull final Player player) {
this.player = player;
}
BasePlayer getPlayerInstance() {
return basePlayer;
Player getPlayerInstance() {
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.View
import android.view.ViewConfiguration
import org.schabi.newpipe.player.BasePlayer
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.savePopupPositionAndSizeToPrefs
import org.schabi.newpipe.util.AnimationUtils
import kotlin.math.abs
import kotlin.math.hypot
@ -18,14 +18,14 @@ import kotlin.math.max
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
* and provides some abstract methods to make it easier separating the logic from the UI.
*/
abstract class BasePlayerGestureListener(
@JvmField
protected val playerImpl: VideoPlayerImpl,
protected val player: Player,
@JvmField
protected val service: MainPlayer
) : GestureDetector.SimpleOnGestureListener(), View.OnTouchListener {
@ -78,7 +78,7 @@ abstract class BasePlayerGestureListener(
// ///////////////////////////////////////////////////////////////////
override fun onTouch(v: View, event: MotionEvent): Boolean {
return if (playerImpl.popupPlayerSelected()) {
return if (player.popupPlayerSelected()) {
onTouchInPopup(v, event)
} else {
onTouchInMain(v, event)
@ -86,14 +86,14 @@ abstract class BasePlayerGestureListener(
}
private fun onTouchInMain(v: View, event: MotionEvent): Boolean {
playerImpl.gestureDetector.onTouchEvent(event)
player.gestureDetector.onTouchEvent(event)
if (event.action == MotionEvent.ACTION_UP && isMovingInMain) {
isMovingInMain = false
onScrollEnd(MainPlayer.PlayerType.VIDEO, event)
}
return when (event.action) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
v.parent.requestDisallowInterceptTouchEvent(playerImpl.isFullscreen)
v.parent.requestDisallowInterceptTouchEvent(player.isFullscreen)
true
}
MotionEvent.ACTION_UP -> {
@ -105,7 +105,7 @@ abstract class BasePlayerGestureListener(
}
private fun onTouchInPopup(v: View, event: MotionEvent): Boolean {
playerImpl.gestureDetector.onTouchEvent(event)
player.gestureDetector.onTouchEvent(event)
if (event.pointerCount == 2 && !isMovingInPopup && !isResizing) {
if (DEBUG) {
Log.d(TAG, "onTouch() 2 finger pointer detected, enabling resizing.")
@ -157,10 +157,10 @@ abstract class BasePlayerGestureListener(
initSecPointerY = (-1).toFloat()
onPopupResizingEnd()
playerImpl.changeState(playerImpl.currentState)
player.changeState(player.currentState)
}
if (!playerImpl.isPopupClosing) {
playerImpl.savePositionAndSize()
if (!player.isPopupClosing) {
savePopupPositionAndSizeToPrefs(player)
}
}
@ -190,19 +190,15 @@ abstract class BasePlayerGestureListener(
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
val newWidth = popupWidth * currentPointerDistance / initPointerDistance
initPointerDistance = currentPointerDistance
playerImpl.popupLayoutParams.x += ((popupWidth - newWidth) / 2.0).toInt()
player.popupLayoutParams!!.x += ((popupWidth - newWidth) / 2.0).toInt()
playerImpl.checkPopupPositionBounds()
playerImpl.updateScreenSize()
playerImpl.updatePopupSize(
min(playerImpl.screenWidth.toDouble(), newWidth).toInt(),
-1
)
player.checkPopupPositionBounds()
player.updateScreenSize()
player.changePopupSize(min(player.screenWidth.toDouble(), newWidth).toInt())
return true
}
}
@ -222,7 +218,7 @@ abstract class BasePlayerGestureListener(
return true
}
return if (playerImpl.popupPlayerSelected())
return if (player.popupPlayerSelected())
onDownInPopup(e)
else
true
@ -231,12 +227,10 @@ abstract class BasePlayerGestureListener(
private fun onDownInPopup(e: MotionEvent): Boolean {
// 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).
playerImpl.updateScreenSize()
playerImpl.checkPopupPositionBounds()
initialPopupX = playerImpl.popupLayoutParams.x
initialPopupY = playerImpl.popupLayoutParams.y
playerImpl.popupWidth = playerImpl.popupLayoutParams.width.toFloat()
playerImpl.popupHeight = playerImpl.popupLayoutParams.height.toFloat()
player.updateScreenSize()
player.checkPopupPositionBounds()
initialPopupX = player.popupLayoutParams!!.x
initialPopupY = player.popupLayoutParams!!.y
return super.onDown(e)
}
@ -255,15 +249,15 @@ abstract class BasePlayerGestureListener(
if (isDoubleTapping)
return true
if (playerImpl.popupPlayerSelected()) {
if (playerImpl.player == null)
if (player.popupPlayerSelected()) {
if (player.exoPlayerIsNull())
return false
onSingleTap(MainPlayer.PlayerType.POPUP)
return true
} else {
super.onSingleTapConfirmed(e)
if (playerImpl.currentState == BasePlayer.STATE_BLOCKED)
if (player.currentState == Player.STATE_BLOCKED)
return true
onSingleTap(MainPlayer.PlayerType.VIDEO)
@ -272,10 +266,10 @@ abstract class BasePlayerGestureListener(
}
override fun onLongPress(e: MotionEvent?) {
if (playerImpl.popupPlayerSelected()) {
playerImpl.updateScreenSize()
playerImpl.checkPopupPositionBounds()
playerImpl.updatePopupSize(playerImpl.screenWidth.toInt(), -1)
if (player.popupPlayerSelected()) {
player.updateScreenSize()
player.checkPopupPositionBounds()
player.changePopupSize(player.screenWidth.toInt())
}
}
@ -285,7 +279,7 @@ abstract class BasePlayerGestureListener(
distanceX: Float,
distanceY: Float
): Boolean {
return if (playerImpl.popupPlayerSelected()) {
return if (player.popupPlayerSelected()) {
onScrollInPopup(initialEvent, movingEvent, distanceX, distanceY)
} else {
onScrollInMain(initialEvent, movingEvent, distanceX, distanceY)
@ -298,19 +292,18 @@ abstract class BasePlayerGestureListener(
velocityX: Float,
velocityY: Float
): Boolean {
return if (playerImpl.popupPlayerSelected()) {
return if (player.popupPlayerSelected()) {
val absVelocityX = abs(velocityX)
val absVelocityY = abs(velocityY)
if (absVelocityX.coerceAtLeast(absVelocityY) > tossFlingVelocity) {
if (absVelocityX > tossFlingVelocity) {
playerImpl.popupLayoutParams.x = velocityX.toInt()
player.popupLayoutParams!!.x = velocityX.toInt()
}
if (absVelocityY > tossFlingVelocity) {
playerImpl.popupLayoutParams.y = velocityY.toInt()
player.popupLayoutParams!!.y = velocityY.toInt()
}
playerImpl.checkPopupPositionBounds()
playerImpl.windowManager
.updateViewLayout(playerImpl.rootView, playerImpl.popupLayoutParams)
player.checkPopupPositionBounds()
player.windowManager!!.updateViewLayout(player.rootView, player.popupLayoutParams)
return true
}
return false
@ -326,13 +319,13 @@ abstract class BasePlayerGestureListener(
distanceY: Float
): Boolean {
if (!playerImpl.isFullscreen) {
if (!player.isFullscreen) {
return false
}
val isTouchingStatusBar: Boolean = initialEvent.y < getStatusBarHeight(service)
val isTouchingNavigationBar: Boolean =
initialEvent.y > (playerImpl.rootView.height - getNavigationBarHeight(service))
initialEvent.y > (player.rootView.height - getNavigationBarHeight(service))
if (isTouchingStatusBar || isTouchingNavigationBar) {
return false
}
@ -340,7 +333,7 @@ abstract class BasePlayerGestureListener(
val insideThreshold = abs(movingEvent.y - initialEvent.y) <= MOVEMENT_THRESHOLD
if (
!isMovingInMain && (insideThreshold || abs(distanceX) > abs(distanceY)) ||
playerImpl.currentState == BasePlayer.STATE_COMPLETED
player.currentState == Player.STATE_COMPLETED
) {
return false
}
@ -371,7 +364,7 @@ abstract class BasePlayerGestureListener(
}
if (!isMovingInPopup) {
AnimationUtils.animateView(playerImpl.closeButton, true, 200)
AnimationUtils.animateView(player.closeOverlayButton, true, 200)
}
isMovingInPopup = true
@ -381,20 +374,20 @@ abstract class BasePlayerGestureListener(
val diffY: Float = (movingEvent.rawY - initialEvent.rawY)
var posY: Float = (initialPopupY + diffY)
if (posX > playerImpl.screenWidth - playerImpl.popupWidth) {
posX = (playerImpl.screenWidth - playerImpl.popupWidth)
if (posX > player.screenWidth - player.popupLayoutParams!!.width) {
posX = (player.screenWidth - player.popupLayoutParams!!.width)
} else if (posX < 0) {
posX = 0f
}
if (posY > playerImpl.screenHeight - playerImpl.popupHeight) {
posY = (playerImpl.screenHeight - playerImpl.popupHeight)
if (posY > player.screenHeight - player.popupLayoutParams!!.height) {
posY = (player.screenHeight - player.popupLayoutParams!!.height)
} else if (posY < 0) {
posY = 0f
}
playerImpl.popupLayoutParams.x = posX.toInt()
playerImpl.popupLayoutParams.y = posY.toInt()
player.popupLayoutParams!!.x = posX.toInt()
player.popupLayoutParams!!.y = posY.toInt()
onScroll(
MainPlayer.PlayerType.POPUP,
@ -405,8 +398,7 @@ abstract class BasePlayerGestureListener(
distanceY
)
playerImpl.windowManager
.updateViewLayout(playerImpl.rootView, playerImpl.popupLayoutParams)
player.windowManager!!.updateViewLayout(player.rootView, player.popupLayoutParams)
return true
}
@ -474,16 +466,16 @@ abstract class BasePlayerGestureListener(
// ///////////////////////////////////////////////////////////////////
private fun getDisplayPortion(e: MotionEvent): DisplayPortion {
return if (playerImpl.playerType == MainPlayer.PlayerType.POPUP) {
return if (player.playerType == MainPlayer.PlayerType.POPUP) {
when {
e.x < playerImpl.popupWidth / 3.0 -> DisplayPortion.LEFT
e.x > playerImpl.popupWidth * 2.0 / 3.0 -> DisplayPortion.RIGHT
e.x < player.popupLayoutParams!!.width / 3.0 -> DisplayPortion.LEFT
e.x > player.popupLayoutParams!!.width * 2.0 / 3.0 -> DisplayPortion.RIGHT
else -> DisplayPortion.MIDDLE
}
} else /* MainPlayer.PlayerType.VIDEO */ {
when {
e.x < playerImpl.rootView.width / 3.0 -> DisplayPortion.LEFT
e.x > playerImpl.rootView.width * 2.0 / 3.0 -> DisplayPortion.RIGHT
e.x < player.rootView.width / 3.0 -> DisplayPortion.LEFT
e.x > player.rootView.width * 2.0 / 3.0 -> DisplayPortion.RIGHT
else -> DisplayPortion.MIDDLE
}
}
@ -491,14 +483,14 @@ abstract class BasePlayerGestureListener(
// Currently needed for scrolling since there is no action more the middle portion
private fun getDisplayHalfPortion(e: MotionEvent): DisplayPortion {
return if (playerImpl.playerType == MainPlayer.PlayerType.POPUP) {
return if (player.playerType == MainPlayer.PlayerType.POPUP) {
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 /* MainPlayer.PlayerType.VIDEO */ {
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
}
}
@ -522,7 +514,7 @@ abstract class BasePlayerGestureListener(
companion object {
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 MOVEMENT_THRESHOLD = 40

View File

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

View File

@ -18,7 +18,7 @@ import androidx.fragment.app.DialogFragment;
import org.schabi.newpipe.R;
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;
public class PlaybackParameterDialog extends DialogFragment {

View File

@ -1,8 +1,15 @@
package org.schabi.newpipe.player.helper;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.os.Build;
import android.provider.Settings;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.CaptioningManager;
import androidx.annotation.IntDef;
@ -11,11 +18,14 @@ import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
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.text.CaptionStyleCompat;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
import com.google.android.exoplayer2.util.MimeTypes;
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.VideoStream;
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.PlayQueueItem;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
@ -41,13 +53,16 @@ import java.util.Formatter;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FILL;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
import static 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_NEVER;
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;
}
@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() { }
////////////////////////////////////////////////////////////////////////////
@ -121,14 +145,16 @@ public final class PlayerHelper {
@NonNull
public static String resizeTypeOf(@NonNull final Context context,
@AspectRatioFrameLayout.ResizeMode final int resizeMode) {
@ResizeMode final int resizeMode) {
switch (resizeMode) {
case RESIZE_MODE_FIT:
case AspectRatioFrameLayout.RESIZE_MODE_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);
case RESIZE_MODE_ZOOM:
case AspectRatioFrameLayout.RESIZE_MODE_ZOOM:
return context.getResources().getString(R.string.resize_zoom);
case AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT:
case AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH:
default:
throw new IllegalArgumentException("Unrecognized resize mode: " + resizeMode);
}
@ -199,23 +225,23 @@ public final class PlayerHelper {
////////////////////////////////////////////////////////////////////////////
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) {
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) {
return isBrightnessGestureEnabled(context, true);
}
public static boolean isRememberingPopupDimensions(@NonNull final Context context) {
return isRememberingPopupDimensions(context, true);
return getPreferences(context)
.getBoolean(context.getString(R.string.brightness_gesture_control_key), true);
}
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) {
@ -229,7 +255,8 @@ public final class PlayerHelper {
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 action = getMinimizeOnExitAction(context, defaultAction);
final String action = getPreferences(context)
.getString(context.getString(R.string.minimize_on_exit_key), defaultAction);
if (action.equals(popupAction)) {
return MINIMIZE_ON_EXIT_MODE_POPUP;
} 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
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))) {
return AUTOPLAY_TYPE_ALWAYS;
} else if (type.equals(context.getString(R.string.autoplay_never_key))) {
@ -350,14 +391,32 @@ public final class PlayerHelper {
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) {
//a value of less than 0, the default, means to use the preferred screen brightness
return getScreenBrightness(context, -1);
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 -1;
} else {
return sp.getFloat(context.getString(R.string.screen_brightness_key), -1);
}
}
public static void setScreenBrightness(@NonNull final Context context,
final float setScreenBrightness) {
setScreenBrightness(context, setScreenBrightness, System.currentTimeMillis());
final float screenBrightness) {
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) {
@ -376,75 +435,11 @@ public final class PlayerHelper {
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) {
return getPreferences(context)
.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(
final StreamInfoItem streamInfoItem) {
final SinglePlayQueue singlePlayQueue = new SinglePlayQueue(streamInfoItem);
@ -452,12 +447,168 @@ public final class PlayerHelper {
return singlePlayQueue;
}
@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;
////////////////////////////////////////////////////////////////////////////
// Utils used by player
////////////////////////////////////////////////////////////////////////////
public static MainPlayer.PlayerType retrievePlayerTypeFromIntent(final Intent intent) {
// 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.extractor.stream.StreamInfo;
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.PlayerServiceExtendedEventListener;
import org.schabi.newpipe.player.playqueue.PlayQueue;
@ -33,7 +33,7 @@ public final class PlayerHolder {
private static ServiceConnection serviceConnection;
public static boolean bound;
private static MainPlayer playerService;
private static VideoPlayerImpl player;
private static Player player;
/**
* 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;
public interface MediaSessionCallback {
void onSkipToPrevious();
void playPrevious();
void onSkipToNext();
void playNext();
void onSkipToIndex(int index);
void playItemAtIndex(int index);
int getCurrentPlayingIndex();
@ -15,7 +15,7 @@ public interface MediaSessionCallback {
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
public void onSkipToPrevious(final Player player, final ControlDispatcher controlDispatcher) {
callback.onSkipToPrevious();
callback.playPrevious();
}
@Override
public void onSkipToQueueItem(final Player player, final ControlDispatcher controlDispatcher,
final long id) {
callback.onSkipToIndex((int) id);
callback.playItemAtIndex((int) id);
}
@Override
public void onSkipToNext(final Player player, final ControlDispatcher controlDispatcher) {
callback.onSkipToNext();
callback.playNext();
}
private void publishFloatingQueueWindow() {

View File

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

View File

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

View File

@ -351,4 +351,19 @@ public final class Localization {
private static double round(final double value, final int places) {
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.subscription.SubscriptionFragment;
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
import org.schabi.newpipe.player.BackgroundPlayerActivity;
import org.schabi.newpipe.player.BasePlayer;
import org.schabi.newpipe.player.PlayQueueActivity;
import org.schabi.newpipe.player.Player;
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.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue;
@ -78,11 +77,11 @@ public final class NavigationHelper {
if (playQueue != null) {
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
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(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_VIDEO);
intent.putExtra(Player.RESUME_PLAYBACK, resumePlayback);
intent.putExtra(Player.PLAYER_TYPE, MainPlayer.PlayerType.VIDEO.ordinal());
return intent;
}
@ -94,7 +93,7 @@ public final class NavigationHelper {
final boolean resumePlayback,
final boolean playWhenReady) {
return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
.putExtra(BasePlayer.PLAY_WHEN_READY, playWhenReady);
.putExtra(Player.PLAY_WHEN_READY, playWhenReady);
}
@NonNull
@ -104,8 +103,8 @@ public final class NavigationHelper {
final boolean selectOnAppend,
final boolean resumePlayback) {
return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
.putExtra(BasePlayer.APPEND_ONLY, true)
.putExtra(BasePlayer.SELECT_ON_APPEND, selectOnAppend);
.putExtra(Player.APPEND_ONLY, true)
.putExtra(Player.SELECT_ON_APPEND, selectOnAppend);
}
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();
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);
}
@ -145,7 +144,7 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT)
.show();
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);
}
@ -162,7 +161,7 @@ public final class NavigationHelper {
final Intent intent = getPlayerEnqueueIntent(
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);
}
@ -182,7 +181,7 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerEnqueueIntent(
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);
}
@ -198,7 +197,7 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
final Intent intent = getPlayerEnqueueIntent(
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);
}
@ -493,7 +492,7 @@ public final class NavigationHelper {
if (playQueue != null) {
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
if (cacheKey != null) {
intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey);
intent.putExtra(Player.PLAY_QUEUE_KEY, cacheKey);
}
}
context.startActivity(intent);
@ -531,7 +530,7 @@ public final class NavigationHelper {
}
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) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".player.BackgroundPlayerActivity">
tools:context=".player.PlayQueueActivity">
<item
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_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="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="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_default_value" translatable="false">10000</string>
<string-array name="seek_duration_description" translatable="false">
@ -70,7 +73,6 @@
<item>@string/minimize_on_exit_popup_description</item>
</string-array>
<string name="autoplay_key" translatable="false">autoplay_key</string>
<string name="autoplay_value" translatable="false">@string/autoplay_wifi_key</string>
<string name="autoplay_always_key" translatable="false">autoplay_always_key</string>

View File

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