Merge branch 'subtitles' of https://github.com/karyogamy/NewPipe into sub
This commit is contained in:
commit
b57d4b3048
9 changed files with 551 additions and 73 deletions
|
@ -35,7 +35,9 @@ import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.TypedValue;
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -48,6 +50,8 @@ import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
|
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||||
|
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
|
@ -61,7 +65,6 @@ import org.schabi.newpipe.util.AnimationUtils;
|
||||||
import org.schabi.newpipe.util.ListHelper;
|
import org.schabi.newpipe.util.ListHelper;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
import org.schabi.newpipe.util.PopupMenuIconHacker;
|
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -194,7 +197,6 @@ public final class MainVideoPlayer extends Activity {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
|
|
||||||
if (playerImpl.isSomePopupMenuVisible()) {
|
if (playerImpl.isSomePopupMenuVisible()) {
|
||||||
playerImpl.moreOptionsPopupMenu.dismiss();
|
|
||||||
playerImpl.getQualityPopupMenu().dismiss();
|
playerImpl.getQualityPopupMenu().dismiss();
|
||||||
playerImpl.getPlaybackSpeedPopupMenu().dismiss();
|
playerImpl.getPlaybackSpeedPopupMenu().dismiss();
|
||||||
}
|
}
|
||||||
|
@ -301,8 +303,11 @@ public final class MainVideoPlayer extends Activity {
|
||||||
private boolean queueVisible;
|
private boolean queueVisible;
|
||||||
|
|
||||||
private ImageButton moreOptionsButton;
|
private ImageButton moreOptionsButton;
|
||||||
public int moreOptionsPopupMenuGroupId = 89;
|
private ImageButton toggleOrientationButton;
|
||||||
public PopupMenu moreOptionsPopupMenu;
|
private ImageButton switchPopupButton;
|
||||||
|
private ImageButton switchBackgroundButton;
|
||||||
|
|
||||||
|
private View secondaryControls;
|
||||||
|
|
||||||
VideoPlayerImpl(final Context context) {
|
VideoPlayerImpl(final Context context) {
|
||||||
super("VideoPlayerImpl" + MainVideoPlayer.TAG, context);
|
super("VideoPlayerImpl" + MainVideoPlayer.TAG, context);
|
||||||
|
@ -322,9 +327,12 @@ public final class MainVideoPlayer extends Activity {
|
||||||
this.playPauseButton = rootView.findViewById(R.id.playPauseButton);
|
this.playPauseButton = rootView.findViewById(R.id.playPauseButton);
|
||||||
this.playPreviousButton = rootView.findViewById(R.id.playPreviousButton);
|
this.playPreviousButton = rootView.findViewById(R.id.playPreviousButton);
|
||||||
this.playNextButton = rootView.findViewById(R.id.playNextButton);
|
this.playNextButton = rootView.findViewById(R.id.playNextButton);
|
||||||
|
|
||||||
this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton);
|
this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton);
|
||||||
this.moreOptionsPopupMenu = new PopupMenu(context, moreOptionsButton);
|
this.secondaryControls = rootView.findViewById(R.id.secondaryControls);
|
||||||
buildMoreOptionsMenu();
|
this.toggleOrientationButton = rootView.findViewById(R.id.toggleOrientation);
|
||||||
|
this.switchBackgroundButton = rootView.findViewById(R.id.switchBackground);
|
||||||
|
this.switchPopupButton = rootView.findViewById(R.id.switchPopup);
|
||||||
|
|
||||||
titleTextView.setSelected(true);
|
titleTextView.setSelected(true);
|
||||||
channelTextView.setSelected(true);
|
channelTextView.setSelected(true);
|
||||||
|
@ -332,6 +340,24 @@ public final class MainVideoPlayer extends Activity {
|
||||||
getRootView().setKeepScreenOn(true);
|
getRootView().setKeepScreenOn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setupSubtitleView(@NonNull SubtitleView view,
|
||||||
|
@NonNull String captionSizeKey) {
|
||||||
|
final float captionRatioInverse;
|
||||||
|
if (captionSizeKey.equals(getString(R.string.smaller_caption_size_key))) {
|
||||||
|
captionRatioInverse = 22f;
|
||||||
|
} else if (captionSizeKey.equals(getString(R.string.larger_caption_size_key))) {
|
||||||
|
captionRatioInverse = 18f;
|
||||||
|
} else {
|
||||||
|
captionRatioInverse = 20f;
|
||||||
|
}
|
||||||
|
|
||||||
|
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||||
|
final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels);
|
||||||
|
view.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||||
|
(float) minimumLength / captionRatioInverse);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initListeners() {
|
public void initListeners() {
|
||||||
super.initListeners();
|
super.initListeners();
|
||||||
|
@ -348,7 +374,11 @@ public final class MainVideoPlayer extends Activity {
|
||||||
playPauseButton.setOnClickListener(this);
|
playPauseButton.setOnClickListener(this);
|
||||||
playPreviousButton.setOnClickListener(this);
|
playPreviousButton.setOnClickListener(this);
|
||||||
playNextButton.setOnClickListener(this);
|
playNextButton.setOnClickListener(this);
|
||||||
|
|
||||||
moreOptionsButton.setOnClickListener(this);
|
moreOptionsButton.setOnClickListener(this);
|
||||||
|
toggleOrientationButton.setOnClickListener(this);
|
||||||
|
switchBackgroundButton.setOnClickListener(this);
|
||||||
|
switchPopupButton.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -464,6 +494,16 @@ public final class MainVideoPlayer extends Activity {
|
||||||
return;
|
return;
|
||||||
} else if (v.getId() == moreOptionsButton.getId()) {
|
} else if (v.getId() == moreOptionsButton.getId()) {
|
||||||
onMoreOptionsClicked();
|
onMoreOptionsClicked();
|
||||||
|
|
||||||
|
} else if (v.getId() == toggleOrientationButton.getId()) {
|
||||||
|
onScreenRotationClicked();
|
||||||
|
|
||||||
|
} else if (v.getId() == switchPopupButton.getId()) {
|
||||||
|
onFullScreenButtonClicked();
|
||||||
|
|
||||||
|
} else if (v.getId() == switchBackgroundButton.getId()) {
|
||||||
|
onPlayBackgroundButtonClicked();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getCurrentState() != STATE_COMPLETED) {
|
if (getCurrentState() != STATE_COMPLETED) {
|
||||||
|
@ -497,8 +537,15 @@ public final class MainVideoPlayer extends Activity {
|
||||||
private void onMoreOptionsClicked() {
|
private void onMoreOptionsClicked() {
|
||||||
if (DEBUG) Log.d(TAG, "onMoreOptionsClicked() called");
|
if (DEBUG) Log.d(TAG, "onMoreOptionsClicked() called");
|
||||||
|
|
||||||
moreOptionsPopupMenu.show();
|
if (secondaryControls.getVisibility() == View.VISIBLE) {
|
||||||
isSomePopupMenuVisible = true;
|
moreOptionsButton.setImageDrawable(getResources().getDrawable(
|
||||||
|
R.drawable.ic_expand_more_white_24dp));
|
||||||
|
animateView(secondaryControls, false, 200);
|
||||||
|
} else {
|
||||||
|
moreOptionsButton.setImageDrawable(getResources().getDrawable(
|
||||||
|
R.drawable.ic_expand_less_white_24dp));
|
||||||
|
animateView(secondaryControls, true, 200);
|
||||||
|
}
|
||||||
showControls(300);
|
showControls(300);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,6 +569,18 @@ public final class MainVideoPlayer extends Activity {
|
||||||
if (isPlaying()) hideControls(300, 0);
|
if (isPlaying()) hideControls(300, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int nextResizeMode(int currentResizeMode) {
|
||||||
|
switch (currentResizeMode) {
|
||||||
|
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
|
||||||
|
return AspectRatioFrameLayout.RESIZE_MODE_FILL;
|
||||||
|
case AspectRatioFrameLayout.RESIZE_MODE_FILL:
|
||||||
|
return AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
|
||||||
|
default:
|
||||||
|
return AspectRatioFrameLayout.RESIZE_MODE_FIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getDefaultResolutionIndex(final List<VideoStream> sortedVideos) {
|
protected int getDefaultResolutionIndex(final List<VideoStream> sortedVideos) {
|
||||||
return ListHelper.getDefaultResolutionIndex(context, sortedVideos);
|
return ListHelper.getDefaultResolutionIndex(context, sortedVideos);
|
||||||
|
@ -637,42 +696,6 @@ public final class MainVideoPlayer extends Activity {
|
||||||
setShuffleButton(shuffleButton, playQueue.isShuffled());
|
setShuffleButton(shuffleButton, playQueue.isShuffled());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildMoreOptionsMenu() {
|
|
||||||
this.moreOptionsPopupMenu.getMenuInflater().inflate(R.menu.menu_videooptions,
|
|
||||||
moreOptionsPopupMenu.getMenu());
|
|
||||||
|
|
||||||
moreOptionsPopupMenu.setOnMenuItemClickListener(menuItem -> {
|
|
||||||
switch (menuItem.getItemId()) {
|
|
||||||
case R.id.toggleOrientation:
|
|
||||||
onScreenRotationClicked();
|
|
||||||
break;
|
|
||||||
case R.id.switchPopup:
|
|
||||||
onFullScreenButtonClicked();
|
|
||||||
break;
|
|
||||||
case R.id.switchBackground:
|
|
||||||
onPlayBackgroundButtonClicked();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
PopupMenuIconHacker.setShowPopupIcon(moreOptionsPopupMenu);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix icon theme
|
|
||||||
if(ThemeHelper.isLightThemeSelected(MainVideoPlayer.this)) {
|
|
||||||
moreOptionsPopupMenu.getMenu()
|
|
||||||
.findItem(R.id.toggleOrientation)
|
|
||||||
.setIcon(R.drawable.ic_screen_rotation_black_24dp);
|
|
||||||
moreOptionsPopupMenu.getMenu()
|
|
||||||
.findItem(R.id.switchPopup)
|
|
||||||
.setIcon(R.drawable.ic_fullscreen_exit_black_24dp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildQueue() {
|
private void buildQueue() {
|
||||||
queueLayout = findViewById(R.id.playQueuePanel);
|
queueLayout = findViewById(R.id.playQueuePanel);
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,11 @@ import android.widget.RemoteViews;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
|
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||||
|
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||||
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
import org.schabi.newpipe.BuildConfig;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
@ -88,6 +91,8 @@ public final class PopupVideoPlayer extends Service {
|
||||||
private static final String POPUP_SAVED_X = "popup_saved_x";
|
private static final String POPUP_SAVED_X = "popup_saved_x";
|
||||||
private static final String POPUP_SAVED_Y = "popup_saved_y";
|
private static final String POPUP_SAVED_Y = "popup_saved_y";
|
||||||
|
|
||||||
|
private static final int MINIMUM_SHOW_EXTRA_WIDTH_DP = 300;
|
||||||
|
|
||||||
private WindowManager windowManager;
|
private WindowManager windowManager;
|
||||||
private WindowManager.LayoutParams windowLayoutParams;
|
private WindowManager.LayoutParams windowLayoutParams;
|
||||||
private GestureDetector gestureDetector;
|
private GestureDetector gestureDetector;
|
||||||
|
@ -358,10 +363,12 @@ public final class PopupVideoPlayer extends Service {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
protected class VideoPlayerImpl extends VideoPlayer {
|
protected class VideoPlayerImpl extends VideoPlayer implements View.OnLayoutChangeListener {
|
||||||
private TextView resizingIndicator;
|
private TextView resizingIndicator;
|
||||||
private ImageButton fullScreenButton;
|
private ImageButton fullScreenButton;
|
||||||
|
|
||||||
|
private View extraOptionsView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleIntent(Intent intent) {
|
public void handleIntent(Intent intent) {
|
||||||
super.handleIntent(intent);
|
super.handleIntent(intent);
|
||||||
|
@ -380,6 +387,29 @@ public final class PopupVideoPlayer extends Service {
|
||||||
resizingIndicator = rootView.findViewById(R.id.resizing_indicator);
|
resizingIndicator = rootView.findViewById(R.id.resizing_indicator);
|
||||||
fullScreenButton = rootView.findViewById(R.id.fullScreenButton);
|
fullScreenButton = rootView.findViewById(R.id.fullScreenButton);
|
||||||
fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked());
|
fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked());
|
||||||
|
|
||||||
|
extraOptionsView = rootView.findViewById(R.id.extraOptionsView);
|
||||||
|
rootView.addOnLayoutChangeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setupSubtitleView(@NonNull SubtitleView view,
|
||||||
|
@NonNull String captionSizeKey) {
|
||||||
|
float captionRatio = SubtitleView.DEFAULT_TEXT_SIZE_FRACTION;
|
||||||
|
if (captionSizeKey.equals(getString(R.string.smaller_caption_size_key))) {
|
||||||
|
captionRatio *= 0.9;
|
||||||
|
} else if (captionSizeKey.equals(getString(R.string.larger_caption_size_key))) {
|
||||||
|
captionRatio *= 1.1;
|
||||||
|
}
|
||||||
|
view.setFractionalTextSize(captionRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLayoutChange(final View view, int left, int top, int right, int bottom,
|
||||||
|
int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||||
|
float widthDp = Math.abs(right - left) / getResources().getDisplayMetrics().density;
|
||||||
|
final int visibility = widthDp > MINIMUM_SHOW_EXTRA_WIDTH_DP ? View.VISIBLE : View.GONE;
|
||||||
|
extraOptionsView.setVisibility(visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -438,6 +468,15 @@ public final class PopupVideoPlayer extends Service {
|
||||||
if (isPlaying()) hideControls(500, 0);
|
if (isPlaying()) hideControls(500, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int nextResizeMode(int resizeMode) {
|
||||||
|
if (resizeMode == AspectRatioFrameLayout.RESIZE_MODE_FILL) {
|
||||||
|
return AspectRatioFrameLayout.RESIZE_MODE_FIT;
|
||||||
|
} else {
|
||||||
|
return AspectRatioFrameLayout.RESIZE_MODE_FILL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
super.onStopTrackingTouch(seekBar);
|
super.onStopTrackingTouch(seekBar);
|
||||||
|
@ -642,8 +681,8 @@ public final class PopupVideoPlayer extends Service {
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
/*package-private*/ void enableVideoRenderer(final boolean enable) {
|
/*package-private*/ void enableVideoRenderer(final boolean enable) {
|
||||||
final int videoRendererIndex = getVideoRendererIndex();
|
final int videoRendererIndex = getRendererIndex(C.TRACK_TYPE_VIDEO);
|
||||||
if (trackSelector != null && videoRendererIndex != -1) {
|
if (trackSelector != null && videoRendererIndex != RENDERER_UNAVAILABLE) {
|
||||||
trackSelector.setRendererDisabled(videoRendererIndex, !enable);
|
trackSelector.setRendererDisabled(videoRendererIndex, !enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,10 @@ import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
@ -46,17 +48,25 @@ import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
|
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||||
|
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.MediaFormat;
|
import org.schabi.newpipe.extractor.MediaFormat;
|
||||||
|
import org.schabi.newpipe.extractor.Subtitles;
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||||
import org.schabi.newpipe.util.AnimationUtils;
|
import org.schabi.newpipe.util.AnimationUtils;
|
||||||
import org.schabi.newpipe.util.ListHelper;
|
import org.schabi.newpipe.util.ListHelper;
|
||||||
|
@ -64,6 +74,8 @@ import org.schabi.newpipe.util.ListHelper;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.C.SELECTION_FLAG_AUTOSELECT;
|
||||||
|
import static com.google.android.exoplayer2.C.TIME_UNSET;
|
||||||
import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed;
|
import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed;
|
||||||
import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
|
import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
@ -88,6 +100,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
// Player
|
// Player
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
protected static final int RENDERER_UNAVAILABLE = -1;
|
||||||
public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds
|
public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds
|
||||||
|
|
||||||
private ArrayList<VideoStream> availableStreams;
|
private ArrayList<VideoStream> availableStreams;
|
||||||
|
@ -123,6 +136,11 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
private View topControlsRoot;
|
private View topControlsRoot;
|
||||||
private TextView qualityTextView;
|
private TextView qualityTextView;
|
||||||
|
|
||||||
|
private SubtitleView subtitleView;
|
||||||
|
|
||||||
|
private TextView resizeView;
|
||||||
|
private TextView captionTextView;
|
||||||
|
|
||||||
private ValueAnimator controlViewAnimator;
|
private ValueAnimator controlViewAnimator;
|
||||||
private Handler controlsVisibilityHandler = new Handler();
|
private Handler controlsVisibilityHandler = new Handler();
|
||||||
|
|
||||||
|
@ -133,6 +151,9 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
private int playbackSpeedPopupMenuGroupId = 79;
|
private int playbackSpeedPopupMenuGroupId = 79;
|
||||||
private PopupMenu playbackSpeedPopupMenu;
|
private PopupMenu playbackSpeedPopupMenu;
|
||||||
|
|
||||||
|
private int captionPopupMenuGroupId = 89;
|
||||||
|
private PopupMenu captionPopupMenu;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public VideoPlayer(String debugTag, Context context) {
|
public VideoPlayer(String debugTag, Context context) {
|
||||||
|
@ -164,6 +185,17 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
this.topControlsRoot = rootView.findViewById(R.id.topControls);
|
this.topControlsRoot = rootView.findViewById(R.id.topControls);
|
||||||
this.qualityTextView = rootView.findViewById(R.id.qualityTextView);
|
this.qualityTextView = rootView.findViewById(R.id.qualityTextView);
|
||||||
|
|
||||||
|
this.subtitleView = rootView.findViewById(R.id.subtitleView);
|
||||||
|
final String captionSizeKey = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
.getString(context.getString(R.string.caption_size_key),
|
||||||
|
context.getString(R.string.caption_size_default));
|
||||||
|
setupSubtitleView(subtitleView, captionSizeKey);
|
||||||
|
|
||||||
|
this.resizeView = rootView.findViewById(R.id.resizeTextView);
|
||||||
|
resizeView.setText(PlayerHelper.resizeTypeOf(context, aspectRatioFrameLayout.getResizeMode()));
|
||||||
|
|
||||||
|
this.captionTextView = rootView.findViewById(R.id.captionTextView);
|
||||||
|
|
||||||
//this.aspectRatioFrameLayout.setAspectRatio(16.0f / 9.0f);
|
//this.aspectRatioFrameLayout.setAspectRatio(16.0f / 9.0f);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
@ -172,25 +204,37 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
|
|
||||||
this.qualityPopupMenu = new PopupMenu(context, qualityTextView);
|
this.qualityPopupMenu = new PopupMenu(context, qualityTextView);
|
||||||
this.playbackSpeedPopupMenu = new PopupMenu(context, playbackSpeedTextView);
|
this.playbackSpeedPopupMenu = new PopupMenu(context, playbackSpeedTextView);
|
||||||
|
this.captionPopupMenu = new PopupMenu(context, captionTextView);
|
||||||
|
|
||||||
((ProgressBar) this.loadingPanel.findViewById(R.id.progressBarLoadingPanel)).getIndeterminateDrawable().setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY);
|
((ProgressBar) this.loadingPanel.findViewById(R.id.progressBarLoadingPanel))
|
||||||
|
.getIndeterminateDrawable().setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void setupSubtitleView(@NonNull SubtitleView view,
|
||||||
|
@NonNull String captionSizeKey);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initListeners() {
|
public void initListeners() {
|
||||||
super.initListeners();
|
super.initListeners();
|
||||||
playbackSeekBar.setOnSeekBarChangeListener(this);
|
playbackSeekBar.setOnSeekBarChangeListener(this);
|
||||||
playbackSpeedTextView.setOnClickListener(this);
|
playbackSpeedTextView.setOnClickListener(this);
|
||||||
qualityTextView.setOnClickListener(this);
|
qualityTextView.setOnClickListener(this);
|
||||||
|
captionTextView.setOnClickListener(this);
|
||||||
|
resizeView.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initPlayer() {
|
public void initPlayer() {
|
||||||
super.initPlayer();
|
super.initPlayer();
|
||||||
|
|
||||||
|
// Setup video view
|
||||||
simpleExoPlayer.setVideoSurfaceView(surfaceView);
|
simpleExoPlayer.setVideoSurfaceView(surfaceView);
|
||||||
simpleExoPlayer.addVideoListener(this);
|
simpleExoPlayer.addVideoListener(this);
|
||||||
|
|
||||||
|
// Setup subtitle view
|
||||||
|
simpleExoPlayer.addTextOutput(cues -> subtitleView.onCues(cues));
|
||||||
|
|
||||||
|
// Setup audio session with onboard equalizer
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
trackSelector.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(context));
|
trackSelector.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(context));
|
||||||
}
|
}
|
||||||
|
@ -236,6 +280,38 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
playbackSpeedPopupMenu.setOnDismissListener(this);
|
playbackSpeedPopupMenu.setOnDismissListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void buildCaptionMenu(final List<String> availableLanguages) {
|
||||||
|
if (captionPopupMenu == null) return;
|
||||||
|
captionPopupMenu.getMenu().removeGroup(captionPopupMenuGroupId);
|
||||||
|
|
||||||
|
// Add option for turning off caption
|
||||||
|
MenuItem captionOffItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId,
|
||||||
|
0, Menu.NONE, R.string.caption_none);
|
||||||
|
captionOffItem.setOnMenuItemClickListener(menuItem -> {
|
||||||
|
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
|
if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||||
|
trackSelector.setRendererDisabled(textRendererIndex, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add all available captions
|
||||||
|
for (int i = 0; i < availableLanguages.size(); i++) {
|
||||||
|
final String captionLanguage = availableLanguages.get(i);
|
||||||
|
MenuItem captionItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId,
|
||||||
|
i + 1, Menu.NONE, captionLanguage);
|
||||||
|
captionItem.setOnMenuItemClickListener(menuItem -> {
|
||||||
|
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
|
if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||||
|
trackSelector.setParameters(trackSelector.getParameters()
|
||||||
|
.withPreferredTextLanguage(captionLanguage));
|
||||||
|
trackSelector.setRendererDisabled(textRendererIndex, false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
captionPopupMenu.setOnDismissListener(this);
|
||||||
|
}
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Playback Listener
|
// Playback Listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -251,7 +327,8 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
playbackSpeedTextView.setVisibility(View.GONE);
|
playbackSpeedTextView.setVisibility(View.GONE);
|
||||||
|
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false);
|
final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context,
|
||||||
|
info.video_streams, info.video_only_streams, false);
|
||||||
availableStreams = new ArrayList<>(videos);
|
availableStreams = new ArrayList<>(videos);
|
||||||
if (playbackQuality == null) {
|
if (playbackQuality == null) {
|
||||||
selectedStreamIndex = getDefaultResolutionIndex(videos);
|
selectedStreamIndex = getDefaultResolutionIndex(videos);
|
||||||
|
@ -280,13 +357,39 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
if (index < 0 || index >= videos.size()) return null;
|
if (index < 0 || index >= videos.size()) return null;
|
||||||
final VideoStream video = videos.get(index);
|
final VideoStream video = videos.get(index);
|
||||||
|
|
||||||
final MediaSource streamSource = buildMediaSource(video.getUrl(), MediaFormat.getSuffixById(video.format));
|
List<MediaSource> mediaSources = new ArrayList<>();
|
||||||
final AudioStream audio = ListHelper.getHighestQualityAudio(info.audio_streams);
|
// Create video stream source
|
||||||
if (!video.isVideoOnly || audio == null) return streamSource;
|
final MediaSource streamSource = buildMediaSource(video.getUrl(),
|
||||||
|
MediaFormat.getSuffixById(video.getFormatId()));
|
||||||
|
mediaSources.add(streamSource);
|
||||||
|
|
||||||
|
// Create optional audio stream source
|
||||||
|
final AudioStream audio = ListHelper.getHighestQualityAudio(info.audio_streams);
|
||||||
|
if (video.isVideoOnly && audio != null) {
|
||||||
// Merge with audio stream in case if video does not contain audio
|
// Merge with audio stream in case if video does not contain audio
|
||||||
final MediaSource audioSource = buildMediaSource(audio.getUrl(), MediaFormat.getSuffixById(audio.format));
|
final MediaSource audioSource = buildMediaSource(audio.getUrl(),
|
||||||
return new MergingMediaSource(streamSource, audioSource);
|
MediaFormat.getSuffixById(audio.getFormatId()));
|
||||||
|
mediaSources.add(audioSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create subtitle sources
|
||||||
|
for (final Subtitles subtitle : info.getSubtitles()) {
|
||||||
|
final String mimeType = PlayerHelper.mimeTypesOf(subtitle.getFileType());
|
||||||
|
if (mimeType == null) continue;
|
||||||
|
|
||||||
|
final Format textFormat = Format.createTextSampleFormat(null, mimeType,
|
||||||
|
SELECTION_FLAG_AUTOSELECT, PlayerHelper.captionLanguageOf(subtitle));
|
||||||
|
final MediaSource textSource = new SingleSampleMediaSource(
|
||||||
|
Uri.parse(subtitle.getURL()), cacheDataSourceFactory, textFormat, TIME_UNSET);
|
||||||
|
mediaSources.add(textSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mediaSources.size() == 1) {
|
||||||
|
return mediaSources.get(0);
|
||||||
|
} else {
|
||||||
|
return new MergingMediaSource(mediaSources.toArray(
|
||||||
|
new MediaSource[mediaSources.size()]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -364,6 +467,12 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
// ExoPlayer Video Listener
|
// ExoPlayer Video Listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||||
|
super.onTracksChanged(trackGroups, trackSelections);
|
||||||
|
onTextTrackUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
|
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -377,6 +486,57 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
animateView(surfaceForeground, false, 100);
|
animateView(surfaceForeground, false, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// ExoPlayer Track Updates
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private void onTextTrackUpdate() {
|
||||||
|
final int textRenderer = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
|
|
||||||
|
if (captionTextView == null) return;
|
||||||
|
if (trackSelector == null || trackSelector.getCurrentMappedTrackInfo() == null ||
|
||||||
|
textRenderer == RENDERER_UNAVAILABLE) {
|
||||||
|
captionTextView.setVisibility(View.GONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final TrackGroupArray textTracks = trackSelector.getCurrentMappedTrackInfo()
|
||||||
|
.getTrackGroups(textRenderer);
|
||||||
|
|
||||||
|
// Extract all loaded languages
|
||||||
|
List<String> availableLanguages = new ArrayList<>(textTracks.length);
|
||||||
|
for (int i = 0; i < textTracks.length; i++) {
|
||||||
|
final TrackGroup textTrack = textTracks.get(i);
|
||||||
|
if (textTrack.length > 0 && textTrack.getFormat(0) != null) {
|
||||||
|
availableLanguages.add(textTrack.getFormat(0).language);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize mismatching language strings
|
||||||
|
final String preferredLanguage = trackSelector.getParameters().preferredTextLanguage;
|
||||||
|
// Because ExoPlayer normalizes the preferred language string but not the text track
|
||||||
|
// language strings, some preferred language string will have the language name in lowercase
|
||||||
|
String formattedPreferredLanguage = null;
|
||||||
|
if (preferredLanguage != null) {
|
||||||
|
for (final String language : availableLanguages) {
|
||||||
|
if (language.compareToIgnoreCase(preferredLanguage) == 0) {
|
||||||
|
formattedPreferredLanguage = language;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build UI
|
||||||
|
buildCaptionMenu(availableLanguages);
|
||||||
|
if (trackSelector.getRendererDisabled(textRenderer) || formattedPreferredLanguage == null ||
|
||||||
|
!availableLanguages.contains(formattedPreferredLanguage)) {
|
||||||
|
captionTextView.setText(R.string.caption_none);
|
||||||
|
} else {
|
||||||
|
captionTextView.setText(formattedPreferredLanguage);
|
||||||
|
}
|
||||||
|
captionTextView.setVisibility(availableLanguages.isEmpty() ? View.GONE : View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// General Player
|
// General Player
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -453,6 +613,10 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
onQualitySelectorClicked();
|
onQualitySelectorClicked();
|
||||||
} else if (v.getId() == playbackSpeedTextView.getId()) {
|
} else if (v.getId() == playbackSpeedTextView.getId()) {
|
||||||
onPlaybackSpeedClicked();
|
onPlaybackSpeedClicked();
|
||||||
|
} else if (v.getId() == resizeView.getId()) {
|
||||||
|
onResizeClicked();
|
||||||
|
} else if (v.getId() == captionTextView.getId()) {
|
||||||
|
onCaptionClicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,6 +680,23 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
showControls(300);
|
showControls(300);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onCaptionClicked() {
|
||||||
|
if (DEBUG) Log.d(TAG, "onCaptionClicked() called");
|
||||||
|
captionPopupMenu.show();
|
||||||
|
isSomePopupMenuVisible = true;
|
||||||
|
showControls(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onResizeClicked() {
|
||||||
|
if (getAspectRatioFrameLayout() != null && context != null) {
|
||||||
|
final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode();
|
||||||
|
final int newResizeMode = nextResizeMode(currentResizeMode);
|
||||||
|
getAspectRatioFrameLayout().setResizeMode(newResizeMode);
|
||||||
|
getResizeView().setText(PlayerHelper.resizeTypeOf(context, newResizeMode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int nextResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode);
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// SeekBar Listener
|
// SeekBar Listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -557,16 +738,16 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
// Utils
|
// Utils
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public int getVideoRendererIndex() {
|
public int getRendererIndex(final int trackIndex) {
|
||||||
if (simpleExoPlayer == null) return -1;
|
if (simpleExoPlayer == null) return RENDERER_UNAVAILABLE;
|
||||||
|
|
||||||
for (int t = 0; t < simpleExoPlayer.getRendererCount(); t++) {
|
for (int t = 0; t < simpleExoPlayer.getRendererCount(); t++) {
|
||||||
if (simpleExoPlayer.getRendererType(t) == C.TRACK_TYPE_VIDEO) {
|
if (simpleExoPlayer.getRendererType(t) == trackIndex) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return RENDERER_UNAVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isControlsVisible() {
|
public boolean isControlsVisible() {
|
||||||
|
@ -755,4 +936,15 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
return currentDisplaySeek;
|
return currentDisplaySeek;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SubtitleView getSubtitleView() {
|
||||||
|
return subtitleView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView getResizeView() {
|
||||||
|
return resizeView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView getCaptionTextView() {
|
||||||
|
return captionTextView;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,12 @@ import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||||
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.Subtitles;
|
||||||
|
import org.schabi.newpipe.extractor.stream.SubtitlesFormat;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
@ -14,6 +19,12 @@ import java.util.Locale;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
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_FIXED_HEIGHT;
|
||||||
|
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH;
|
||||||
|
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
|
||||||
|
|
||||||
public class PlayerHelper {
|
public class PlayerHelper {
|
||||||
private PlayerHelper() {}
|
private PlayerHelper() {}
|
||||||
|
|
||||||
|
@ -46,6 +57,30 @@ public class PlayerHelper {
|
||||||
return pitchFormatter.format(pitch);
|
return pitchFormatter.format(pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String mimeTypesOf(final SubtitlesFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case VTT: return MimeTypes.TEXT_VTT;
|
||||||
|
case TTML: return MimeTypes.APPLICATION_TTML;
|
||||||
|
default: throw new IllegalArgumentException("Unrecognized mime type: " + format.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String captionLanguageOf(@NonNull final Subtitles subtitles) {
|
||||||
|
final String displayName = subtitles.getLocale().getDisplayName(subtitles.getLocale());
|
||||||
|
return displayName + (subtitles.isAutoGenerated() ? " (auto-generated)" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String resizeTypeOf(@NonNull final Context context,
|
||||||
|
@AspectRatioFrameLayout.ResizeMode final int resizeMode) {
|
||||||
|
switch (resizeMode) {
|
||||||
|
case RESIZE_MODE_FIT: return context.getResources().getString(R.string.resize_fit);
|
||||||
|
case RESIZE_MODE_FILL: return context.getResources().getString(R.string.resize_fill);
|
||||||
|
case RESIZE_MODE_ZOOM: return context.getResources().getString(R.string.resize_zoom);
|
||||||
|
default: throw new IllegalArgumentException("Unrecognized resize mode: " + resizeMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
|
public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
|
||||||
return isResumeAfterAudioFocusGain(context, false);
|
return isResumeAfterAudioFocusGain(context, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,12 @@
|
||||||
|
|
||||||
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout>
|
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout>
|
||||||
|
|
||||||
|
<com.google.android.exoplayer2.ui.SubtitleView
|
||||||
|
android:id="@+id/subtitleView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/endScreen"
|
android:id="@+id/endScreen"
|
||||||
|
@ -139,13 +145,14 @@
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:background="@drawable/player_top_controls_bg"
|
android:background="@drawable/player_top_controls_bg"
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:paddingBottom="70dp"
|
|
||||||
android:paddingLeft="2dp"
|
|
||||||
android:paddingRight="10dp"
|
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:paddingRight="5dp"
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/metadataView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
|
@ -202,6 +209,7 @@
|
||||||
android:text="720p"
|
android:text="720p"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="HardcodedText,RtlHardcoded"/>
|
tools:ignore="HardcodedText,RtlHardcoded"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -215,6 +223,7 @@
|
||||||
android:minWidth="40dp"
|
android:minWidth="40dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="RtlHardcoded,RtlSymmetry"
|
tools:ignore="RtlHardcoded,RtlSymmetry"
|
||||||
tools:text="1x" />
|
tools:text="1x" />
|
||||||
|
|
||||||
|
@ -225,12 +234,12 @@
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_marginLeft="2dp"
|
||||||
android:layout_marginRight="2dp"
|
android:layout_marginRight="2dp"
|
||||||
android:layout_toLeftOf="@+id/moreOptionsButton"
|
android:layout_toLeftOf="@+id/moreOptionsButton"
|
||||||
android:background="#00ffffff"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitXY"
|
||||||
android:src="@drawable/list"
|
android:src="@drawable/list"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -240,13 +249,109 @@
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_marginLeft="2dp"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:background="#00ffffff"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitXY"
|
||||||
android:src="@drawable/ic_more_vert_white_24dp"
|
android:src="@drawable/ic_expand_more_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/secondaryControls"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/topControls"
|
||||||
|
android:gravity="top"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:paddingRight="5dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/resizeTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="35dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minWidth="50dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="HardcodedText,RtlHardcoded"
|
||||||
|
tools:text="FIT"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/captionTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_toLeftOf="@id/switchBackground"
|
||||||
|
android:layout_toRightOf="@id/resizeTextView"
|
||||||
|
android:gravity="center|left"
|
||||||
|
android:minHeight="35dp"
|
||||||
|
android:minWidth="40dp"
|
||||||
|
android:paddingLeft="2dp"
|
||||||
|
android:paddingRight="2dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="RelativeOverlap,RtlHardcoded"
|
||||||
|
tools:text="English" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/toggleOrientation"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_screen_rotation_white"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/toggle_orientation"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/switchPopup"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:layout_toLeftOf="@id/toggleOrientation"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_fullscreen_exit_white"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/switch_to_popup"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/switchBackground"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:layout_toLeftOf="@id/switchPopup"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_headset_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/switch_to_background"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -293,7 +398,6 @@
|
||||||
tools:ignore="HardcodedText"
|
tools:ignore="HardcodedText"
|
||||||
tools:text="1:23:49"/>
|
tools:text="1:23:49"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -379,7 +483,10 @@
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
|
android:layout_toEndOf="@+id/loading_panel"
|
||||||
|
android:layout_toRightOf="@+id/loading_panel"
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
@ -28,6 +28,10 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/black"/>
|
android:background="@android:color/black"/>
|
||||||
|
|
||||||
|
<com.google.android.exoplayer2.ui.SubtitleView
|
||||||
|
android:id="@+id/subtitleView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout>
|
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout>
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,6 +74,7 @@
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="RtlHardcoded,RtlSymmetry"
|
tools:ignore="RtlHardcoded,RtlSymmetry"
|
||||||
tools:text="1080p60"/>
|
tools:text="1080p60"/>
|
||||||
|
|
||||||
|
@ -79,24 +84,61 @@
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
android:layout_toRightOf="@+id/qualityTextView"
|
android:layout_toRightOf="@+id/qualityTextView"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="6dp"
|
android:padding="5dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="RelativeOverlap,RtlHardcoded,RtlSymmetry"
|
tools:ignore="RelativeOverlap,RtlHardcoded,RtlSymmetry"
|
||||||
tools:text="1.75x"/>
|
tools:text="1.75x"/>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/extraOptionsView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_toRightOf="@+id/playbackSpeed"
|
||||||
|
android:layout_toLeftOf="@id/fullScreenButton"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/resizeTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minWidth="50dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="HardcodedText,RtlHardcoded"
|
||||||
|
tools:text="FIT"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/captionTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:layout_toRightOf="@id/resizeTextView"
|
||||||
|
android:gravity="center|left"
|
||||||
|
android:minWidth="40dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="RelativeOverlap,RtlHardcoded,RtlSymmetry"
|
||||||
|
tools:text="English" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/fullScreenButton"
|
android:id="@+id/fullScreenButton"
|
||||||
android:layout_width="30dp"
|
android:layout_width="30dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:background="#00ffffff"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
android:src="@drawable/ic_fullscreen_white"
|
android:src="@drawable/ic_fullscreen_white"
|
||||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<!--Shadow Bottom Control-->
|
<!--Shadow Bottom Control-->
|
||||||
|
|
|
@ -100,6 +100,25 @@
|
||||||
<item>@string/black_theme_title</item>
|
<item>@string/black_theme_title</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Caption Size -->
|
||||||
|
<string name="caption_size_key" translatable="false">caption_size_key</string>
|
||||||
|
<string name="caption_size_default" translatable="false">@string/normal_caption_size_key</string>
|
||||||
|
|
||||||
|
<string name="smaller_caption_size_key" translatable="false">smaller_caption_size</string>
|
||||||
|
<string name="normal_caption_size_key" translatable="false">normal_caption_size</string>
|
||||||
|
<string name="larger_caption_size_key" translatable="false">larger_caption_size</string>
|
||||||
|
|
||||||
|
<string-array name="caption_size_descriptions_list" translatable="false">
|
||||||
|
<item>@string/smaller_caption_font_size</item>
|
||||||
|
<item>@string/normal_caption_font_size</item>
|
||||||
|
<item>@string/larger_caption_font_size</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="caption_size_values_list" translatable="false">
|
||||||
|
<item>@string/smaller_caption_size_key</item>
|
||||||
|
<item>@string/normal_caption_size_key</item>
|
||||||
|
<item>@string/larger_caption_size_key</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<!-- Content & History -->
|
<!-- Content & History -->
|
||||||
<string name="show_search_suggestions_key" translatable="false">show_search_suggestions</string>
|
<string name="show_search_suggestions_key" translatable="false">show_search_suggestions</string>
|
||||||
<string name="show_play_with_kodi_key" translatable="false">show_play_with_kodi</string>
|
<string name="show_play_with_kodi_key" translatable="false">show_play_with_kodi</string>
|
||||||
|
|
|
@ -397,4 +397,17 @@
|
||||||
<string name="playlist_add_stream_success">Added to playlist</string>
|
<string name="playlist_add_stream_success">Added to playlist</string>
|
||||||
<string name="playlist_thumbnail_change_success">Playlist thumbnail changed</string>
|
<string name="playlist_thumbnail_change_success">Playlist thumbnail changed</string>
|
||||||
<string name="playlist_delete_failure">Failed to delete playlist</string>
|
<string name="playlist_delete_failure">Failed to delete playlist</string>
|
||||||
|
|
||||||
|
<!-- Players -->
|
||||||
|
<string name="caption_none">No Caption</string>
|
||||||
|
|
||||||
|
<string name="resize_fit">FIT</string>
|
||||||
|
<string name="resize_fill">FILL</string>
|
||||||
|
<string name="resize_zoom">ZOOM</string>
|
||||||
|
|
||||||
|
<string name="caption_font_size_settings_title">Caption Font Size</string>
|
||||||
|
<string name="smaller_caption_font_size">Smaller Font</string>
|
||||||
|
<string name="normal_caption_font_size">Normal Font</string>
|
||||||
|
<string name="larger_caption_font_size">Larger Font</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -21,4 +21,12 @@
|
||||||
android:key="@string/show_hold_to_append_key"
|
android:key="@string/show_hold_to_append_key"
|
||||||
android:title="@string/show_hold_to_append_title"
|
android:title="@string/show_hold_to_append_title"
|
||||||
android:summary="@string/show_hold_to_append_summary"/>
|
android:summary="@string/show_hold_to_append_summary"/>
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="@string/caption_size_default"
|
||||||
|
android:entries="@array/caption_size_descriptions_list"
|
||||||
|
android:entryValues="@array/caption_size_values_list"
|
||||||
|
android:key="@string/caption_size_key"
|
||||||
|
android:summary="%s"
|
||||||
|
android:title="@string/caption_font_size_settings_title"/>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
Loading…
Reference in a new issue