-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.
This commit is contained in:
John Zhen Mo 2018-02-07 13:11:19 -08:00
parent 6485327b97
commit 880676d670
7 changed files with 142 additions and 75 deletions

View file

@ -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,7 @@ 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 org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
@ -334,6 +337,8 @@ public final class MainVideoPlayer extends Activity {
channelTextView.setSelected(true); channelTextView.setSelected(true);
getRootView().setKeepScreenOn(true); getRootView().setKeepScreenOn(true);
getSubtitleView().setFixedTextSize(TypedValue.COMPLEX_UNIT_PX,
getCaptionSizePx(context));
} }
@Override @Override
@ -547,6 +552,24 @@ public final class MainVideoPlayer extends Activity {
if (isPlaying()) hideControls(300, 0); 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 @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);
@ -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 // Getters
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////

View file

@ -52,6 +52,7 @@ import android.widget.TextView;
import com.google.android.exoplayer2.C; 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 org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R; 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_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;
@ -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 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);
@ -381,6 +386,17 @@ 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
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
@ -439,6 +455,22 @@ public final class PopupVideoPlayer extends Service {
if (isPlaying()) hideControls(500, 0); 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 @Override
public void onStopTrackingTouch(SeekBar seekBar) { public void onStopTrackingTouch(SeekBar seekBar) {
super.onStopTrackingTouch(seekBar); super.onStopTrackingTouch(seekBar);

View file

@ -36,7 +36,6 @@ 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;
import android.util.Log; import android.util.Log;
import android.util.TypedValue;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.SurfaceView; 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.SELECTION_FLAG_AUTOSELECT;
import static com.google.android.exoplayer2.C.TIME_UNSET; 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.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;
@ -204,9 +202,6 @@ public abstract class VideoPlayer extends BasePlayer
((ProgressBar) this.loadingPanel.findViewById(R.id.progressBarLoadingPanel)) ((ProgressBar) this.loadingPanel.findViewById(R.id.progressBarLoadingPanel))
.getIndeterminateDrawable().setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY); .getIndeterminateDrawable().setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY);
subtitleView.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX,
PlayerHelper.getCaptionSizePx(context));
} }
@Override @Override
@ -281,8 +276,10 @@ public abstract class VideoPlayer extends BasePlayer
captionPopupMenu.getMenu().removeGroup(captionPopupMenuGroupId); captionPopupMenu.getMenu().removeGroup(captionPopupMenuGroupId);
if (availableCaptions == null || trackSelector == null) return; if (availableCaptions == null || trackSelector == null) return;
// Add option for turning off caption
MenuItem captionOffItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId, MenuItem captionOffItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId,
0, Menu.NONE, "Caption Off"); 0, Menu.NONE, R.string.caption_none);
captionOffItem.setOnMenuItemClickListener(menuItem -> { captionOffItem.setOnMenuItemClickListener(menuItem -> {
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT); final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
if (trackSelector != null && textRendererIndex != -1) { if (trackSelector != null && textRendererIndex != -1) {
@ -291,6 +288,7 @@ public abstract class VideoPlayer extends BasePlayer
return true; return true;
}); });
// Add all available captions
for (int i = 0; i < availableCaptions.size(); i++) { for (int i = 0; i < availableCaptions.size(); i++) {
final Subtitles subtitles = availableCaptions.get(i); final Subtitles subtitles = availableCaptions.get(i);
final String captionLanguage = PlayerHelper.captionLanguageOf(subtitles); final String captionLanguage = PlayerHelper.captionLanguageOf(subtitles);
@ -306,7 +304,6 @@ public abstract class VideoPlayer extends BasePlayer
return true; return true;
}); });
} }
//captionPopupMenu.setOnMenuItemClickListener(this);
captionPopupMenu.setOnDismissListener(this); captionPopupMenu.setOnDismissListener(this);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -334,14 +331,14 @@ public abstract class VideoPlayer extends BasePlayer
selectedStreamIndex = getOverrideResolutionIndex(videos, getPlaybackQuality()); selectedStreamIndex = getOverrideResolutionIndex(videos, getPlaybackQuality());
} }
availableCaptions = info.getSubtitles();
buildQualityMenu(); buildQualityMenu();
buildPlaybackSpeedMenu(); buildPlaybackSpeedMenu();
buildCaptionMenu(); buildCaptionMenu();
qualityTextView.setVisibility(View.VISIBLE); qualityTextView.setVisibility(View.VISIBLE);
playbackSpeedTextView.setVisibility(View.VISIBLE); playbackSpeedTextView.setVisibility(View.VISIBLE);
captionTextView.setVisibility(availableCaptions.isEmpty() ? View.GONE : View.VISIBLE);
availableCaptions = info.getSubtitles();
if (!availableCaptions.isEmpty()) captionTextView.setVisibility(View.VISIBLE);
} }
} }
@ -472,11 +469,13 @@ public abstract class VideoPlayer extends BasePlayer
@Override @Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
super.onTracksChanged(trackGroups, 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) { trackSelector.getParameters().preferredTextLanguage == null) {
captionTextView.setText("No Caption"); captionTextView.setText(R.string.caption_none);
} else { } else {
final String preferredLanguage = trackSelector.getParameters().preferredTextLanguage; final String preferredLanguage = trackSelector.getParameters().preferredTextLanguage;
captionTextView.setText(preferredLanguage); captionTextView.setText(preferredLanguage);
@ -646,20 +645,7 @@ public abstract class VideoPlayer extends BasePlayer
showControls(300); showControls(300);
} }
protected void onResizeClicked() { protected abstract 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 // SeekBar Listener
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -899,4 +885,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;
}
} }

View file

@ -4,7 +4,6 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.DisplayMetrics;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
@ -75,22 +74,13 @@ public class PlayerHelper {
public static String resizeTypeOf(@NonNull final Context context, public static String resizeTypeOf(@NonNull final Context context,
@AspectRatioFrameLayout.ResizeMode final int resizeMode) { @AspectRatioFrameLayout.ResizeMode final int resizeMode) {
switch (resizeMode) { switch (resizeMode) {
case RESIZE_MODE_FIT: return "FIT"; case RESIZE_MODE_FIT: return context.getResources().getString(R.string.resize_fit);
case RESIZE_MODE_FILL: return "FILL"; case RESIZE_MODE_FILL: return context.getResources().getString(R.string.resize_fill);
case RESIZE_MODE_FIXED_HEIGHT: return "HEIGHT"; case RESIZE_MODE_ZOOM: return context.getResources().getString(R.string.resize_zoom);
case RESIZE_MODE_FIXED_WIDTH: return "WIDTH";
case RESIZE_MODE_ZOOM: return "ZOOM";
default: throw new IllegalArgumentException("Unrecognized resize mode: " + resizeMode); 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) { public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
return isResumeAfterAudioFocusGain(context, false); return isResumeAfterAudioFocusGain(context, false);
} }

View file

@ -286,12 +286,13 @@
<TextView <TextView
android:id="@+id/captionTextView" android:id="@+id/captionTextView"
android:layout_width="80dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:layout_toLeftOf="@id/switchBackground"
android:layout_toRightOf="@id/resizeTextView" android:layout_toRightOf="@id/resizeTextView"
android:gravity="center" android:gravity="center|left"
android:minHeight="35dp" android:minHeight="35dp"
android:minWidth="40dp" android:minWidth="40dp"
android:paddingLeft="2dp" android:paddingLeft="2dp"
@ -299,7 +300,7 @@
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textStyle="bold" android:textStyle="bold"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
tools:ignore="RtlHardcoded" tools:ignore="RelativeOverlap,RtlHardcoded"
tools:text="English" /> tools:text="English" />
<ImageButton <ImageButton

View file

@ -74,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"/>
@ -83,54 +84,63 @@
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"/>
<ImageButton <RelativeLayout
android:id="@+id/fullScreenButton" android:id="@+id/extraOptionsView"
android:layout_width="30dp" android:layout_width="wrap_content"
android:layout_height="30dp" android:layout_height="30dp"
android:layout_alignParentRight="true" android:layout_toRightOf="@+id/playbackSpeed"
android:background="#00ffffff" android:layout_toLeftOf="@id/fullScreenButton"
android:clickable="true" android:visibility="gone">
android:focusable="true"
android:scaleType="fitCenter"
android:src="@drawable/ic_fullscreen_white"
tools:ignore="ContentDescription,RtlHardcoded"/>
<TextView <TextView
android:id="@+id/resizeTextView" android:id="@+id/resizeTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="35dp" android:layout_height="match_parent"
android:padding="5dp" android:padding="5dp"
android:layout_below="@id/qualityTextView"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:gravity="center" android:gravity="center"
android:minWidth="50dp" android:minWidth="50dp"
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"
tools:text="FIT"/> tools:text="FIT"/>
<TextView <TextView
android:id="@+id/captionTextView" android:id="@+id/captionTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:padding="5dp" android:padding="5dp"
android:layout_below="@id/qualityTextView"
android:layout_toRightOf="@id/resizeTextView" android:layout_toRightOf="@id/resizeTextView"
android:gravity="center" android:gravity="center|left"
android:minHeight="35dp"
android:minWidth="40dp" android:minWidth="40dp"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textStyle="bold" android:textStyle="bold"
tools:ignore="RtlHardcoded,RtlSymmetry" android:background="?attr/selectableItemBackground"
tools:ignore="RelativeOverlap,RtlHardcoded,RtlSymmetry"
tools:text="English" /> tools:text="English" />
</RelativeLayout> </RelativeLayout>
<ImageButton
android:id="@+id/fullScreenButton"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:clickable="true"
android:focusable="true"
android:scaleType="fitCenter"
android:background="?attr/selectableItemBackground"
android:src="@drawable/ic_fullscreen_white"
tools:ignore="ContentDescription,RtlHardcoded"/>
</RelativeLayout>
<!--Shadow Bottom Control--> <!--Shadow Bottom Control-->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -395,4 +395,12 @@
<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>
</resources> </resources>