From 5773152ed35a87ca10df7bc39215a966d0fc2e02 Mon Sep 17 00:00:00 2001 From: John Zhen Mo Date: Sat, 3 Feb 2018 14:39:03 -0800 Subject: [PATCH 1/6] -Added subtitles loading and display. -Added subtitles switching button to popup and main players. -Added aspect ratio switching button to popup pand main players. --- .../newpipe/player/PopupVideoPlayer.java | 3 +- .../schabi/newpipe/player/VideoPlayer.java | 164 ++++++++++++++++-- .../newpipe/player/helper/PlayerHelper.java | 45 +++++ .../main/res/layout/activity_main_player.xml | 40 ++++- app/src/main/res/layout/player_popup.xml | 32 ++++ 5 files changed, 272 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index c3803f0d5..e8ccba7d0 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -49,6 +49,7 @@ import android.widget.RemoteViews; import android.widget.SeekBar; import android.widget.TextView; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; @@ -642,7 +643,7 @@ public final class PopupVideoPlayer extends Service { //////////////////////////////////////////////////////////////////////////*/ /*package-private*/ void enableVideoRenderer(final boolean enable) { - final int videoRendererIndex = getVideoRendererIndex(); + final int videoRendererIndex = getRendererIndex(C.TRACK_TYPE_VIDEO); if (trackSelector != null && videoRendererIndex != -1) { trackSelector.setRendererDisabled(videoRendererIndex, !enable); } diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index 5399ff047..48d10a4ad 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -29,12 +29,14 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PorterDuff; +import android.net.Uri; import android.os.Build; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.Log; +import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; import android.view.SurfaceView; @@ -46,17 +48,24 @@ import android.widget.SeekBar; import android.widget.TextView; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MergingMediaSource; +import com.google.android.exoplayer2.source.SingleSampleMediaSource; +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.SubtitleView; import org.schabi.newpipe.R; 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.StreamInfo; import org.schabi.newpipe.extractor.stream.VideoStream; +import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.ListHelper; @@ -64,6 +73,9 @@ import org.schabi.newpipe.util.ListHelper; import java.util.ArrayList; 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 com.google.android.exoplayer2.C.TRACK_TYPE_TEXT; import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed; import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString; import static org.schabi.newpipe.util.AnimationUtils.animateView; @@ -95,6 +107,8 @@ public abstract class VideoPlayer extends BasePlayer protected String playbackQuality; + private List availableCaptions; + protected boolean wasPlaying = false; /*////////////////////////////////////////////////////////////////////////// @@ -123,6 +137,11 @@ public abstract class VideoPlayer extends BasePlayer private View topControlsRoot; private TextView qualityTextView; + private SubtitleView subtitleView; + + private TextView resizeView; + private TextView captionTextView; + private ValueAnimator controlViewAnimator; private Handler controlsVisibilityHandler = new Handler(); @@ -133,6 +152,9 @@ public abstract class VideoPlayer extends BasePlayer private int playbackSpeedPopupMenuGroupId = 79; private PopupMenu playbackSpeedPopupMenu; + private int captionPopupMenuGroupId = 89; + private PopupMenu captionPopupMenu; + /////////////////////////////////////////////////////////////////////////// public VideoPlayer(String debugTag, Context context) { @@ -163,6 +185,12 @@ public abstract class VideoPlayer extends BasePlayer this.bottomControlsRoot = rootView.findViewById(R.id.bottomControls); this.topControlsRoot = rootView.findViewById(R.id.topControls); this.qualityTextView = rootView.findViewById(R.id.qualityTextView); + this.subtitleView = rootView.findViewById(R.id.subtitleView); + + 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); @@ -172,9 +200,13 @@ public abstract class VideoPlayer extends BasePlayer this.qualityPopupMenu = new PopupMenu(context, qualityTextView); 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); + subtitleView.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX, + PlayerHelper.getCaptionSizePx(context)); } @Override @@ -183,14 +215,22 @@ public abstract class VideoPlayer extends BasePlayer playbackSeekBar.setOnSeekBarChangeListener(this); playbackSpeedTextView.setOnClickListener(this); qualityTextView.setOnClickListener(this); + captionTextView.setOnClickListener(this); + resizeView.setOnClickListener(this); } @Override public void initPlayer() { super.initPlayer(); + + // Setup video view simpleExoPlayer.setVideoSurfaceView(surfaceView); simpleExoPlayer.addVideoListener(this); + // Setup subtitle view + simpleExoPlayer.addTextOutput(cues -> subtitleView.onCues(cues)); + + // Setup audio session with onboard equalizer if (Build.VERSION.SDK_INT >= 21) { trackSelector.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(context)); } @@ -236,6 +276,39 @@ public abstract class VideoPlayer extends BasePlayer playbackSpeedPopupMenu.setOnDismissListener(this); } + private void buildCaptionMenu() { + if (captionPopupMenu == null) return; + captionPopupMenu.getMenu().removeGroup(captionPopupMenuGroupId); + + if (availableCaptions == null || trackSelector == null) return; + MenuItem captionOffItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId, + 0, Menu.NONE, "Caption Off"); + captionOffItem.setOnMenuItemClickListener(menuItem -> { + final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT); + if (trackSelector != null && textRendererIndex != -1) { + trackSelector.setRendererDisabled(textRendererIndex, true); + } + return true; + }); + + for (int i = 0; i < availableCaptions.size(); i++) { + final Subtitles subtitles = availableCaptions.get(i); + final String captionLanguage = PlayerHelper.captionLanguageOf(subtitles); + 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 != -1) { + trackSelector.setRendererDisabled(textRendererIndex, false); + trackSelector.setParameters(trackSelector.getParameters() + .withPreferredTextLanguage(captionLanguage)); + } + return true; + }); + } + //captionPopupMenu.setOnMenuItemClickListener(this); + captionPopupMenu.setOnDismissListener(this); + } /*////////////////////////////////////////////////////////////////////////// // Playback Listener //////////////////////////////////////////////////////////////////////////*/ @@ -249,9 +322,11 @@ public abstract class VideoPlayer extends BasePlayer super.sync(item, info); qualityTextView.setVisibility(View.GONE); playbackSpeedTextView.setVisibility(View.GONE); + captionTextView.setVisibility(View.GONE); if (info != null) { - final List videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); + final List videos = ListHelper.getSortedStreamVideosList(context, + info.video_streams, info.video_only_streams, false); availableStreams = new ArrayList<>(videos); if (playbackQuality == null) { selectedStreamIndex = getDefaultResolutionIndex(videos); @@ -261,8 +336,12 @@ public abstract class VideoPlayer extends BasePlayer buildQualityMenu(); buildPlaybackSpeedMenu(); + buildCaptionMenu(); qualityTextView.setVisibility(View.VISIBLE); playbackSpeedTextView.setVisibility(View.VISIBLE); + + availableCaptions = info.getSubtitles(); + if (!availableCaptions.isEmpty()) captionTextView.setVisibility(View.VISIBLE); } } @@ -280,13 +359,39 @@ public abstract class VideoPlayer extends BasePlayer if (index < 0 || index >= videos.size()) return null; final VideoStream video = videos.get(index); - final MediaSource streamSource = buildMediaSource(video.getUrl(), MediaFormat.getSuffixById(video.format)); - final AudioStream audio = ListHelper.getHighestQualityAudio(info.audio_streams); - if (!video.isVideoOnly || audio == null) return streamSource; + List mediaSources = new ArrayList<>(); + // Create video stream source + final MediaSource streamSource = buildMediaSource(video.getUrl(), + MediaFormat.getSuffixById(video.getFormatId())); + mediaSources.add(streamSource); - // Merge with audio stream in case if video does not contain audio - final MediaSource audioSource = buildMediaSource(audio.getUrl(), MediaFormat.getSuffixById(audio.format)); - return new MergingMediaSource(streamSource, audioSource); + // 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 + final MediaSource audioSource = buildMediaSource(audio.getUrl(), + 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 +469,20 @@ public abstract class VideoPlayer extends BasePlayer // ExoPlayer Video Listener //////////////////////////////////////////////////////////////////////////*/ + @Override + public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { + super.onTracksChanged(trackGroups, trackSelections); + if (trackSelector == null || captionTextView == null) return; + + if (trackSelector.getRendererDisabled(getRendererIndex(C.TRACK_TYPE_TEXT)) || + trackSelector.getParameters().preferredTextLanguage == null) { + captionTextView.setText("No Caption"); + } else { + final String preferredLanguage = trackSelector.getParameters().preferredTextLanguage; + captionTextView.setText(preferredLanguage); + } + } + @Override public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { if (DEBUG) { @@ -453,6 +572,10 @@ public abstract class VideoPlayer extends BasePlayer onQualitySelectorClicked(); } else if (v.getId() == playbackSpeedTextView.getId()) { onPlaybackSpeedClicked(); + } else if (v.getId() == resizeView.getId()) { + onResizeClicked(); + } else if (v.getId() == captionTextView.getId()) { + onCaptionClicked(); } } @@ -516,6 +639,27 @@ public abstract class VideoPlayer extends BasePlayer showControls(300); } + private void onCaptionClicked() { + if (DEBUG) Log.d(TAG, "onCaptionClicked() called"); + captionPopupMenu.show(); + isSomePopupMenuVisible = true; + showControls(300); + } + + protected void onResizeClicked() { + if (aspectRatioFrameLayout != null && context != null) { + final int currentResizeMode = aspectRatioFrameLayout.getResizeMode(); + final int newResizeMode; + if (currentResizeMode == AspectRatioFrameLayout.RESIZE_MODE_ZOOM) { + newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT; + } else { + newResizeMode = currentResizeMode + 1; + } + + aspectRatioFrameLayout.setResizeMode(newResizeMode); + resizeView.setText(PlayerHelper.resizeTypeOf(context, newResizeMode)); + } + } /*////////////////////////////////////////////////////////////////////////// // SeekBar Listener //////////////////////////////////////////////////////////////////////////*/ @@ -557,11 +701,11 @@ public abstract class VideoPlayer extends BasePlayer // Utils //////////////////////////////////////////////////////////////////////////*/ - public int getVideoRendererIndex() { + public int getRendererIndex(final int trackIndex) { if (simpleExoPlayer == null) return -1; for (int t = 0; t < simpleExoPlayer.getRendererCount(); t++) { - if (simpleExoPlayer.getRendererType(t) == C.TRACK_TYPE_VIDEO) { + if (simpleExoPlayer.getRendererType(t) == trackIndex) { return t; } } diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java index 40063ba40..75ea3bdc6 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java @@ -4,8 +4,14 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.annotation.NonNull; +import android.util.DisplayMetrics; + +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; +import com.google.android.exoplayer2.util.MimeTypes; 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.NumberFormat; @@ -14,6 +20,12 @@ import java.util.Locale; 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 { private PlayerHelper() {} @@ -46,6 +58,39 @@ public class PlayerHelper { 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 "FIT"; + case RESIZE_MODE_FILL: return "FILL"; + case RESIZE_MODE_FIXED_HEIGHT: return "HEIGHT"; + case RESIZE_MODE_FIXED_WIDTH: return "WIDTH"; + case RESIZE_MODE_ZOOM: return "ZOOM"; + default: throw new IllegalArgumentException("Unrecognized resize mode: " + resizeMode); + } + } + + public static float getCaptionSizePx(@NonNull final Context context) { + final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels); + // todo: expose size control to users + return (float) minimumLength / 20f; + } + public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) { return isResumeAfterAudioFocusGain(context, false); } diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml index 36222f5bc..785505df9 100644 --- a/app/src/main/res/layout/activity_main_player.xml +++ b/app/src/main/res/layout/activity_main_player.xml @@ -30,6 +30,12 @@ + + + + - + @@ -97,6 +101,34 @@ android:src="@drawable/ic_fullscreen_white" tools:ignore="ContentDescription,RtlHardcoded"/> + + + From 6485327b9711f73687b12cb39eb67a991e5fc7f8 Mon Sep 17 00:00:00 2001 From: John Zhen Mo Date: Tue, 6 Feb 2018 15:07:49 -0800 Subject: [PATCH 2/6] -Replace main player dropdown menu with expand/collapse custom UI. --- .../newpipe/player/MainVideoPlayer.java | 77 +++++++-------- .../main/res/layout/activity_main_player.xml | 94 ++++++++++++++++--- 2 files changed, 114 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index 8081dcad7..a23290486 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -61,7 +61,6 @@ import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.PermissionHelper; -import org.schabi.newpipe.util.PopupMenuIconHacker; import org.schabi.newpipe.util.ThemeHelper; import java.util.List; @@ -194,7 +193,6 @@ public final class MainVideoPlayer extends Activity { super.onConfigurationChanged(newConfig); if (playerImpl.isSomePopupMenuVisible()) { - playerImpl.moreOptionsPopupMenu.dismiss(); playerImpl.getQualityPopupMenu().dismiss(); playerImpl.getPlaybackSpeedPopupMenu().dismiss(); } @@ -301,8 +299,11 @@ public final class MainVideoPlayer extends Activity { private boolean queueVisible; private ImageButton moreOptionsButton; - public int moreOptionsPopupMenuGroupId = 89; - public PopupMenu moreOptionsPopupMenu; + private ImageButton toggleOrientationButton; + private ImageButton switchPopupButton; + private ImageButton switchBackgroundButton; + + private View secondaryControls; VideoPlayerImpl(final Context context) { super("VideoPlayerImpl" + MainVideoPlayer.TAG, context); @@ -322,9 +323,12 @@ public final class MainVideoPlayer extends Activity { this.playPauseButton = rootView.findViewById(R.id.playPauseButton); this.playPreviousButton = rootView.findViewById(R.id.playPreviousButton); this.playNextButton = rootView.findViewById(R.id.playNextButton); + this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton); - this.moreOptionsPopupMenu = new PopupMenu(context, moreOptionsButton); - buildMoreOptionsMenu(); + this.secondaryControls = rootView.findViewById(R.id.secondaryControls); + this.toggleOrientationButton = rootView.findViewById(R.id.toggleOrientation); + this.switchBackgroundButton = rootView.findViewById(R.id.switchBackground); + this.switchPopupButton = rootView.findViewById(R.id.switchPopup); titleTextView.setSelected(true); channelTextView.setSelected(true); @@ -348,7 +352,11 @@ public final class MainVideoPlayer extends Activity { playPauseButton.setOnClickListener(this); playPreviousButton.setOnClickListener(this); playNextButton.setOnClickListener(this); + moreOptionsButton.setOnClickListener(this); + toggleOrientationButton.setOnClickListener(this); + switchBackgroundButton.setOnClickListener(this); + switchPopupButton.setOnClickListener(this); } /*////////////////////////////////////////////////////////////////////////// @@ -464,6 +472,16 @@ public final class MainVideoPlayer extends Activity { return; } else if (v.getId() == moreOptionsButton.getId()) { 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) { @@ -497,8 +515,15 @@ public final class MainVideoPlayer extends Activity { private void onMoreOptionsClicked() { if (DEBUG) Log.d(TAG, "onMoreOptionsClicked() called"); - moreOptionsPopupMenu.show(); - isSomePopupMenuVisible = true; + if (secondaryControls.getVisibility() == View.VISIBLE) { + 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); } @@ -637,42 +662,6 @@ public final class MainVideoPlayer extends Activity { 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() { queueLayout = findViewById(R.id.playQueuePanel); diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml index 785505df9..577a6a8f5 100644 --- a/app/src/main/res/layout/activity_main_player.xml +++ b/app/src/main/res/layout/activity_main_player.xml @@ -145,10 +145,10 @@ android:layout_alignParentTop="true" android:background="@drawable/player_top_controls_bg" android:gravity="top" - android:paddingBottom="70dp" - android:paddingLeft="2dp" - android:paddingRight="10dp" android:paddingTop="10dp" + android:paddingBottom="10dp" + android:paddingLeft="5dp" + android:paddingRight="5dp" tools:ignore="RtlHardcoded"> @@ -232,12 +234,12 @@ android:layout_marginLeft="2dp" android:layout_marginRight="2dp" android:layout_toLeftOf="@+id/moreOptionsButton" - android:background="#00ffffff" android:clickable="true" android:focusable="true" android:padding="5dp" android:scaleType="fitXY" android:src="@drawable/list" + android:background="?attr/selectableItemBackground" tools:ignore="ContentDescription,RtlHardcoded"/> + + + + + + + + + + tools:visibility="visible" /> + tools:visibility="visible" /> + tools:visibility="visible" /> From 880676d67028bc23ad8d8df85be4532e807588e1 Mon Sep 17 00:00:00 2001 From: John Zhen Mo Date: Wed, 7 Feb 2018 13:11:19 -0800 Subject: [PATCH 3/6] -Modified popup video player to show extra options only when screen is large enough. -Modified available resize options for different player modes. -Fixed caption menu not working on popup player. -Extracted hardcoded strings. -Added button effects to both main and popup players. --- .../newpipe/player/MainVideoPlayer.java | 29 ++++++++ .../newpipe/player/PopupVideoPlayer.java | 34 ++++++++- .../schabi/newpipe/player/VideoPlayer.java | 51 +++++++------ .../newpipe/player/helper/PlayerHelper.java | 16 +---- .../main/res/layout/activity_main_player.xml | 7 +- app/src/main/res/layout/player_popup.xml | 72 +++++++++++-------- app/src/main/res/values/strings.xml | 8 +++ 7 files changed, 142 insertions(+), 75 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index a23290486..49ce06a9b 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -35,7 +35,9 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; +import android.util.DisplayMetrics; import android.util.Log; +import android.util.TypedValue; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; @@ -48,6 +50,7 @@ import android.widget.TextView; import android.widget.Toast; import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.stream.StreamInfo; @@ -334,6 +337,8 @@ public final class MainVideoPlayer extends Activity { channelTextView.setSelected(true); getRootView().setKeepScreenOn(true); + getSubtitleView().setFixedTextSize(TypedValue.COMPLEX_UNIT_PX, + getCaptionSizePx(context)); } @Override @@ -547,6 +552,24 @@ public final class MainVideoPlayer extends Activity { if (isPlaying()) hideControls(300, 0); } + @Override + protected void onResizeClicked() { + if (getAspectRatioFrameLayout() != null && context != null) { + final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode(); + final int newResizeMode; + if (currentResizeMode == AspectRatioFrameLayout.RESIZE_MODE_FIT) { + newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL; + } else if (currentResizeMode == AspectRatioFrameLayout.RESIZE_MODE_FILL) { + newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM; + } else { + newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT; + } + + getAspectRatioFrameLayout().setResizeMode(newResizeMode); + getResizeView().setText(PlayerHelper.resizeTypeOf(context, newResizeMode)); + } + } + @Override protected int getDefaultResolutionIndex(final List sortedVideos) { return ListHelper.getDefaultResolutionIndex(context, sortedVideos); @@ -745,6 +768,12 @@ public final class MainVideoPlayer extends Activity { }; } + private float getCaptionSizePx(@NonNull Context context) { + final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels); + // todo: expose size control to users + return (float) minimumLength / 20f; + } /////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index e8ccba7d0..bf6d6f445 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -52,6 +52,7 @@ import android.widget.TextView; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.R; @@ -89,6 +90,8 @@ public final class PopupVideoPlayer extends Service { private static final String POPUP_SAVED_X = "popup_saved_x"; 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.LayoutParams windowLayoutParams; private GestureDetector gestureDetector; @@ -359,10 +362,12 @@ public final class PopupVideoPlayer extends Service { /////////////////////////////////////////////////////////////////////////// - protected class VideoPlayerImpl extends VideoPlayer { + protected class VideoPlayerImpl extends VideoPlayer implements View.OnLayoutChangeListener { private TextView resizingIndicator; private ImageButton fullScreenButton; + private View extraOptionsView; + @Override public void handleIntent(Intent intent) { super.handleIntent(intent); @@ -381,6 +386,17 @@ public final class PopupVideoPlayer extends Service { resizingIndicator = rootView.findViewById(R.id.resizing_indicator); fullScreenButton = rootView.findViewById(R.id.fullScreenButton); fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked()); + + extraOptionsView = rootView.findViewById(R.id.extraOptionsView); + rootView.addOnLayoutChangeListener(this); + } + + @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 @@ -439,6 +455,22 @@ public final class PopupVideoPlayer extends Service { if (isPlaying()) hideControls(500, 0); } + @Override + protected void onResizeClicked() { + if (getAspectRatioFrameLayout() != null && context != null) { + final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode(); + final int newResizeMode; + if (currentResizeMode == AspectRatioFrameLayout.RESIZE_MODE_FILL) { + newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT; + } else { + newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL; + } + + getAspectRatioFrameLayout().setResizeMode(newResizeMode); + getResizeView().setText(PlayerHelper.resizeTypeOf(context, newResizeMode)); + } + } + @Override public void onStopTrackingTouch(SeekBar seekBar) { super.onStopTrackingTouch(seekBar); diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index 48d10a4ad..344175030 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -36,7 +36,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.Log; -import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; import android.view.SurfaceView; @@ -75,7 +74,6 @@ 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 com.google.android.exoplayer2.C.TRACK_TYPE_TEXT; import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed; import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString; import static org.schabi.newpipe.util.AnimationUtils.animateView; @@ -204,9 +202,6 @@ public abstract class VideoPlayer extends BasePlayer ((ProgressBar) this.loadingPanel.findViewById(R.id.progressBarLoadingPanel)) .getIndeterminateDrawable().setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY); - - subtitleView.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX, - PlayerHelper.getCaptionSizePx(context)); } @Override @@ -281,8 +276,10 @@ public abstract class VideoPlayer extends BasePlayer captionPopupMenu.getMenu().removeGroup(captionPopupMenuGroupId); if (availableCaptions == null || trackSelector == null) return; + + // Add option for turning off caption MenuItem captionOffItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId, - 0, Menu.NONE, "Caption Off"); + 0, Menu.NONE, R.string.caption_none); captionOffItem.setOnMenuItemClickListener(menuItem -> { final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT); if (trackSelector != null && textRendererIndex != -1) { @@ -291,6 +288,7 @@ public abstract class VideoPlayer extends BasePlayer return true; }); + // Add all available captions for (int i = 0; i < availableCaptions.size(); i++) { final Subtitles subtitles = availableCaptions.get(i); final String captionLanguage = PlayerHelper.captionLanguageOf(subtitles); @@ -306,7 +304,6 @@ public abstract class VideoPlayer extends BasePlayer return true; }); } - //captionPopupMenu.setOnMenuItemClickListener(this); captionPopupMenu.setOnDismissListener(this); } /*////////////////////////////////////////////////////////////////////////// @@ -334,14 +331,14 @@ public abstract class VideoPlayer extends BasePlayer selectedStreamIndex = getOverrideResolutionIndex(videos, getPlaybackQuality()); } + availableCaptions = info.getSubtitles(); + buildQualityMenu(); buildPlaybackSpeedMenu(); buildCaptionMenu(); qualityTextView.setVisibility(View.VISIBLE); playbackSpeedTextView.setVisibility(View.VISIBLE); - - availableCaptions = info.getSubtitles(); - if (!availableCaptions.isEmpty()) captionTextView.setVisibility(View.VISIBLE); + captionTextView.setVisibility(availableCaptions.isEmpty() ? View.GONE : View.VISIBLE); } } @@ -472,11 +469,13 @@ public abstract class VideoPlayer extends BasePlayer @Override public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { super.onTracksChanged(trackGroups, trackSelections); - if (trackSelector == null || captionTextView == null) return; + if (captionTextView == null) return; - if (trackSelector.getRendererDisabled(getRendererIndex(C.TRACK_TYPE_TEXT)) || + if (trackSelector == null) { + captionTextView.setVisibility(View.GONE); + } else if (trackSelector.getRendererDisabled(getRendererIndex(C.TRACK_TYPE_TEXT)) || trackSelector.getParameters().preferredTextLanguage == null) { - captionTextView.setText("No Caption"); + captionTextView.setText(R.string.caption_none); } else { final String preferredLanguage = trackSelector.getParameters().preferredTextLanguage; captionTextView.setText(preferredLanguage); @@ -646,20 +645,7 @@ public abstract class VideoPlayer extends BasePlayer showControls(300); } - protected void onResizeClicked() { - if (aspectRatioFrameLayout != null && context != null) { - final int currentResizeMode = aspectRatioFrameLayout.getResizeMode(); - final int newResizeMode; - if (currentResizeMode == AspectRatioFrameLayout.RESIZE_MODE_ZOOM) { - newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT; - } else { - newResizeMode = currentResizeMode + 1; - } - - aspectRatioFrameLayout.setResizeMode(newResizeMode); - resizeView.setText(PlayerHelper.resizeTypeOf(context, newResizeMode)); - } - } + protected abstract void onResizeClicked(); /*////////////////////////////////////////////////////////////////////////// // SeekBar Listener //////////////////////////////////////////////////////////////////////////*/ @@ -899,4 +885,15 @@ public abstract class VideoPlayer extends BasePlayer return currentDisplaySeek; } + public SubtitleView getSubtitleView() { + return subtitleView; + } + + public TextView getResizeView() { + return resizeView; + } + + public TextView getCaptionTextView() { + return captionTextView; + } } diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java index 75ea3bdc6..476838f13 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java @@ -4,7 +4,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.annotation.NonNull; -import android.util.DisplayMetrics; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import com.google.android.exoplayer2.util.MimeTypes; @@ -75,22 +74,13 @@ public class PlayerHelper { public static String resizeTypeOf(@NonNull final Context context, @AspectRatioFrameLayout.ResizeMode final int resizeMode) { switch (resizeMode) { - case RESIZE_MODE_FIT: return "FIT"; - case RESIZE_MODE_FILL: return "FILL"; - case RESIZE_MODE_FIXED_HEIGHT: return "HEIGHT"; - case RESIZE_MODE_FIXED_WIDTH: return "WIDTH"; - case RESIZE_MODE_ZOOM: return "ZOOM"; + 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 float getCaptionSizePx(@NonNull final Context context) { - final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels); - // todo: expose size control to users - return (float) minimumLength / 20f; - } - public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) { return isResumeAfterAudioFocusGain(context, false); } diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml index 577a6a8f5..80c67974f 100644 --- a/app/src/main/res/layout/activity_main_player.xml +++ b/app/src/main/res/layout/activity_main_player.xml @@ -286,12 +286,13 @@ @@ -83,52 +84,61 @@ android:layout_height="30dp" android:layout_toRightOf="@+id/qualityTextView" android:gravity="center" - android:padding="6dp" + android:padding="5dp" android:textColor="@android:color/white" android:textStyle="bold" + android:background="?attr/selectableItemBackground" tools:ignore="RelativeOverlap,RtlHardcoded,RtlSymmetry" tools:text="1.75x"/> + + + + + + + - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 767bffa10..b1bd5c3ec 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -395,4 +395,12 @@ Added to playlist Playlist thumbnail changed Failed to delete playlist + + + No Caption + + FIT + FILL + ZOOM + From f506fc0478cbed1df0387880c9b1513d0f233169 Mon Sep 17 00:00:00 2001 From: John Zhen Mo Date: Fri, 9 Feb 2018 12:43:24 -0800 Subject: [PATCH 4/6] -Moved caption extraction and menu building into exoplayer track changing callback. -Updated extractor dependency. --- .../newpipe/player/PopupVideoPlayer.java | 2 +- .../schabi/newpipe/player/VideoPlayer.java | 89 +++++++++++++------ 2 files changed, 61 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index bf6d6f445..9b5413977 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -676,7 +676,7 @@ public final class PopupVideoPlayer extends Service { /*package-private*/ void enableVideoRenderer(final boolean enable) { final int videoRendererIndex = getRendererIndex(C.TRACK_TYPE_VIDEO); - if (trackSelector != null && videoRendererIndex != -1) { + if (trackSelector != null && videoRendererIndex != RENDERER_UNAVAILABLE) { trackSelector.setRendererDisabled(videoRendererIndex, !enable); } } diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index 344175030..7f41c028f 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -53,6 +53,7 @@ import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.source.MediaSource; 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; @@ -98,6 +99,7 @@ public abstract class VideoPlayer extends BasePlayer // Player //////////////////////////////////////////////////////////////////////////*/ + protected static final int RENDERER_UNAVAILABLE = -1; public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds private ArrayList availableStreams; @@ -105,8 +107,6 @@ public abstract class VideoPlayer extends BasePlayer protected String playbackQuality; - private List availableCaptions; - protected boolean wasPlaying = false; /*////////////////////////////////////////////////////////////////////////// @@ -271,35 +271,32 @@ public abstract class VideoPlayer extends BasePlayer playbackSpeedPopupMenu.setOnDismissListener(this); } - private void buildCaptionMenu() { + private void buildCaptionMenu(final List availableLanguages) { if (captionPopupMenu == null) return; captionPopupMenu.getMenu().removeGroup(captionPopupMenuGroupId); - if (availableCaptions == null || trackSelector == null) return; - // 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 != -1) { + if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) { trackSelector.setRendererDisabled(textRendererIndex, true); } return true; }); // Add all available captions - for (int i = 0; i < availableCaptions.size(); i++) { - final Subtitles subtitles = availableCaptions.get(i); - final String captionLanguage = PlayerHelper.captionLanguageOf(subtitles); + 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 != -1) { - trackSelector.setRendererDisabled(textRendererIndex, false); + if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) { trackSelector.setParameters(trackSelector.getParameters() .withPreferredTextLanguage(captionLanguage)); + trackSelector.setRendererDisabled(textRendererIndex, false); } return true; }); @@ -319,7 +316,6 @@ public abstract class VideoPlayer extends BasePlayer super.sync(item, info); qualityTextView.setVisibility(View.GONE); playbackSpeedTextView.setVisibility(View.GONE); - captionTextView.setVisibility(View.GONE); if (info != null) { final List videos = ListHelper.getSortedStreamVideosList(context, @@ -331,14 +327,10 @@ public abstract class VideoPlayer extends BasePlayer selectedStreamIndex = getOverrideResolutionIndex(videos, getPlaybackQuality()); } - availableCaptions = info.getSubtitles(); - buildQualityMenu(); buildPlaybackSpeedMenu(); - buildCaptionMenu(); qualityTextView.setVisibility(View.VISIBLE); playbackSpeedTextView.setVisibility(View.VISIBLE); - captionTextView.setVisibility(availableCaptions.isEmpty() ? View.GONE : View.VISIBLE); } } @@ -469,17 +461,7 @@ public abstract class VideoPlayer extends BasePlayer @Override public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { super.onTracksChanged(trackGroups, trackSelections); - if (captionTextView == null) return; - - if (trackSelector == null) { - captionTextView.setVisibility(View.GONE); - } else if (trackSelector.getRendererDisabled(getRendererIndex(C.TRACK_TYPE_TEXT)) || - trackSelector.getParameters().preferredTextLanguage == null) { - captionTextView.setText(R.string.caption_none); - } else { - final String preferredLanguage = trackSelector.getParameters().preferredTextLanguage; - captionTextView.setText(preferredLanguage); - } + onTextTrackUpdate(); } @Override @@ -495,6 +477,55 @@ public abstract class VideoPlayer extends BasePlayer 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 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; + } + } + + // 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 //////////////////////////////////////////////////////////////////////////*/ @@ -688,7 +719,7 @@ public abstract class VideoPlayer extends BasePlayer //////////////////////////////////////////////////////////////////////////*/ 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++) { if (simpleExoPlayer.getRendererType(t) == trackIndex) { @@ -696,7 +727,7 @@ public abstract class VideoPlayer extends BasePlayer } } - return -1; + return RENDERER_UNAVAILABLE; } public boolean isControlsVisible() { From 59f85838950b5dae0c7e154efed817ab14ed2cb2 Mon Sep 17 00:00:00 2001 From: John Zhen Mo Date: Fri, 9 Feb 2018 13:26:03 -0800 Subject: [PATCH 5/6] -Added settings for managing caption font size. --- .../newpipe/player/MainVideoPlayer.java | 27 +++++++++++++------ .../newpipe/player/PopupVideoPlayer.java | 13 +++++++++ .../schabi/newpipe/player/VideoPlayer.java | 9 +++++++ app/src/main/res/values/settings_keys.xml | 19 +++++++++++++ app/src/main/res/values/strings.xml | 5 ++++ app/src/main/res/xml/appearance_settings.xml | 8 ++++++ 6 files changed, 73 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index 49ce06a9b..5e19e8173 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -51,6 +51,7 @@ import android.widget.Toast; 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.extractor.stream.StreamInfo; @@ -337,8 +338,24 @@ public final class MainVideoPlayer extends Activity { channelTextView.setSelected(true); getRootView().setKeepScreenOn(true); - getSubtitleView().setFixedTextSize(TypedValue.COMPLEX_UNIT_PX, - getCaptionSizePx(context)); + } + + @Override + protected void setupSubtitleView(@NonNull SubtitleView view, + @NonNull String captionSizeKey) { + final float captionRatio; + if (captionSizeKey.equals(getString(R.string.smaller_caption_size_key))) { + captionRatio = 22f; + } else if (captionSizeKey.equals(getString(R.string.larger_caption_size_key))) { + captionRatio = 18f; + } else { + captionRatio = 20f; + } + + final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels); + view.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX, + (float) minimumLength / captionRatio); } @Override @@ -768,12 +785,6 @@ public final class MainVideoPlayer extends Activity { }; } - private float getCaptionSizePx(@NonNull Context context) { - final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels); - // todo: expose size control to users - return (float) minimumLength / 20f; - } /////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index 9b5413977..bda2b7aa5 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -53,6 +53,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.PlaybackParameters; 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.R; @@ -391,6 +392,18 @@ public final class PopupVideoPlayer extends Service { 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) { diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index 7f41c028f..a2f5d22ae 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -32,6 +32,7 @@ import android.graphics.PorterDuff; import android.net.Uri; import android.os.Build; import android.os.Handler; +import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; @@ -183,7 +184,12 @@ public abstract class VideoPlayer extends BasePlayer this.bottomControlsRoot = rootView.findViewById(R.id.bottomControls); this.topControlsRoot = rootView.findViewById(R.id.topControls); 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())); @@ -204,6 +210,9 @@ public abstract class VideoPlayer extends BasePlayer .getIndeterminateDrawable().setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY); } + protected abstract void setupSubtitleView(@NonNull SubtitleView view, + @NonNull String captionSizeKey); + @Override public void initListeners() { super.initListeners(); diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 372b917e0..047f03f8b 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -100,6 +100,25 @@ @string/black_theme_title + + caption_size_key + @string/normal_caption_size_key + + smaller_caption_size + normal_caption_size + larger_caption_size + + + @string/smaller_caption_font_size + @string/normal_caption_font_size + @string/larger_caption_font_size + + + @string/smaller_caption_size_key + @string/normal_caption_size_key + @string/larger_caption_size_key + + show_search_suggestions show_play_with_kodi diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b1bd5c3ec..7ceec994b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -403,4 +403,9 @@ FILL ZOOM + Caption Font Size + Smaller Font + Normal Font + Larger Font + diff --git a/app/src/main/res/xml/appearance_settings.xml b/app/src/main/res/xml/appearance_settings.xml index 58b08a284..3ffbd9d81 100644 --- a/app/src/main/res/xml/appearance_settings.xml +++ b/app/src/main/res/xml/appearance_settings.xml @@ -21,4 +21,12 @@ android:key="@string/show_hold_to_append_key" android:title="@string/show_hold_to_append_title" android:summary="@string/show_hold_to_append_summary"/> + + From f09b04dce0c87b7dc4d3039e02101b8e96b460db Mon Sep 17 00:00:00 2001 From: John Zhen Mo Date: Sat, 10 Feb 2018 19:33:48 -0800 Subject: [PATCH 6/6] -Code clean up on resize switching. --- .../newpipe/player/MainVideoPlayer.java | 32 ++++++++----------- .../newpipe/player/PopupVideoPlayer.java | 17 +++------- .../schabi/newpipe/player/VideoPlayer.java | 15 +++++++-- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index 5e19e8173..d48994d0f 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -343,19 +343,19 @@ public final class MainVideoPlayer extends Activity { @Override protected void setupSubtitleView(@NonNull SubtitleView view, @NonNull String captionSizeKey) { - final float captionRatio; + final float captionRatioInverse; if (captionSizeKey.equals(getString(R.string.smaller_caption_size_key))) { - captionRatio = 22f; + captionRatioInverse = 22f; } else if (captionSizeKey.equals(getString(R.string.larger_caption_size_key))) { - captionRatio = 18f; + captionRatioInverse = 18f; } else { - captionRatio = 20f; + 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 / captionRatio); + (float) minimumLength / captionRatioInverse); } @Override @@ -570,20 +570,14 @@ public final class MainVideoPlayer extends Activity { } @Override - protected void onResizeClicked() { - if (getAspectRatioFrameLayout() != null && context != null) { - final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode(); - final int newResizeMode; - if (currentResizeMode == AspectRatioFrameLayout.RESIZE_MODE_FIT) { - newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL; - } else if (currentResizeMode == AspectRatioFrameLayout.RESIZE_MODE_FILL) { - newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM; - } else { - newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT; - } - - getAspectRatioFrameLayout().setResizeMode(newResizeMode); - getResizeView().setText(PlayerHelper.resizeTypeOf(context, newResizeMode)); + 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; } } diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index bda2b7aa5..f4e7a0d6a 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -469,18 +469,11 @@ public final class PopupVideoPlayer extends Service { } @Override - protected void onResizeClicked() { - if (getAspectRatioFrameLayout() != null && context != null) { - final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode(); - final int newResizeMode; - if (currentResizeMode == AspectRatioFrameLayout.RESIZE_MODE_FILL) { - newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT; - } else { - newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL; - } - - getAspectRatioFrameLayout().setResizeMode(newResizeMode); - getResizeView().setText(PlayerHelper.resizeTypeOf(context, newResizeMode)); + protected int nextResizeMode(int resizeMode) { + if (resizeMode == AspectRatioFrameLayout.RESIZE_MODE_FILL) { + return AspectRatioFrameLayout.RESIZE_MODE_FIT; + } else { + return AspectRatioFrameLayout.RESIZE_MODE_FILL; } } diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index a2f5d22ae..a0bc7223f 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -519,8 +519,10 @@ public abstract class VideoPlayer extends BasePlayer String formattedPreferredLanguage = null; if (preferredLanguage != null) { for (final String language : availableLanguages) { - if (language.compareToIgnoreCase(preferredLanguage) == 0) + if (language.compareToIgnoreCase(preferredLanguage) == 0) { formattedPreferredLanguage = language; + break; + } } } @@ -685,7 +687,16 @@ public abstract class VideoPlayer extends BasePlayer showControls(300); } - protected abstract void onResizeClicked(); + 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 //////////////////////////////////////////////////////////////////////////*/