-Enabled play queue control in main video player.

-Fixed video players does not resolve to preferred quality on playlists.
-Refactored resolution conversion to Localization.
-Fixed video player quality menu building exception when stream info is not yet available.
This commit is contained in:
John Zhen M 2017-10-12 20:47:12 -07:00 committed by John Zhen Mo
parent 87fca5cffe
commit b597774bb9
6 changed files with 223 additions and 17 deletions

View File

@ -754,15 +754,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
} }
} }
private static int resolutionOf(final String resolution) {
final String[] candidates = TextUtils.split(resolution, "p");
if (candidates.length > 0 && TextUtils.isDigitsOnly(candidates[0])) {
return Integer.parseInt(candidates[0]);
} else {
return Integer.MAX_VALUE;
}
}
private void openPopupPlayer(final boolean append) { private void openPopupPlayer(final boolean append) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) {
Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG); Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG);
@ -785,7 +776,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
if (append) { if (append) {
intent = NavigationHelper.getPlayerIntent(activity, PopupVideoPlayer.class, playQueue, true); intent = NavigationHelper.getPlayerIntent(activity, PopupVideoPlayer.class, playQueue, true);
} else { } else {
intent = NavigationHelper.getPlayerIntent(activity, PopupVideoPlayer.class, playQueue, resolutionOf(candidate.resolution)); intent = NavigationHelper.getPlayerIntent(activity, PopupVideoPlayer.class, playQueue, Localization.resolutionOf(candidate.resolution));
} }
activity.startService(intent); activity.startService(intent);
} }
@ -853,7 +844,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
// ExoPlayer // ExoPlayer
final PlayQueue playQueue = new SinglePlayQueue(currentInfo); final PlayQueue playQueue = new SinglePlayQueue(currentInfo);
final VideoStream candidate = sortedStreamVideosList.get(actionBarHandler.getSelectedVideoStream()); final VideoStream candidate = sortedStreamVideosList.get(actionBarHandler.getSelectedVideoStream());
mIntent = NavigationHelper.getPlayerIntent(activity, MainVideoPlayer.class, playQueue, resolutionOf(candidate.resolution)); mIntent = NavigationHelper.getPlayerIntent(activity, MainVideoPlayer.class, playQueue, Localization.resolutionOf(candidate.resolution));
} else { } else {
// Internal Player // Internal Player
mIntent = new Intent(activity, PlayVideoActivity.class) mIntent = new Intent(activity, PlayVideoActivity.class)

View File

@ -28,6 +28,9 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log; import android.util.Log;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -35,6 +38,7 @@ import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.RelativeLayout;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -45,7 +49,10 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.playlist.PlayQueueItem;
import org.schabi.newpipe.playlist.PlayQueueItemBuilder;
import org.schabi.newpipe.playlist.PlayQueueItemHolder;
import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.Localization;
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.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
@ -159,6 +166,7 @@ public final class MainVideoPlayer extends Activity {
private void showSystemUi() { private void showSystemUi() {
if (DEBUG) Log.d(TAG, "showSystemUi() called"); if (DEBUG) Log.d(TAG, "showSystemUi() called");
if (playerImpl != null && playerImpl.queueVisible) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
getWindow().getDecorView().setSystemUiVisibility( getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE View.SYSTEM_UI_FLAG_LAYOUT_STABLE
@ -212,10 +220,18 @@ public final class MainVideoPlayer extends Activity {
private TextView volumeTextView; private TextView volumeTextView;
private TextView brightnessTextView; private TextView brightnessTextView;
private ImageButton repeatButton; private ImageButton repeatButton;
private ImageButton queueButton;
private ImageButton screenRotationButton; private ImageButton screenRotationButton;
private ImageButton playPauseButton; private ImageButton playPauseButton;
private RelativeLayout queueLayout;
private ImageButton itemsListCloseButton;
private RecyclerView itemsList;
private ItemTouchHelper itemTouchHelper;
private boolean queueVisible;
VideoPlayerImpl() { VideoPlayerImpl() {
super("VideoPlayerImpl" + MainVideoPlayer.TAG, MainVideoPlayer.this); super("VideoPlayerImpl" + MainVideoPlayer.TAG, MainVideoPlayer.this);
} }
@ -228,6 +244,7 @@ public final class MainVideoPlayer extends Activity {
this.volumeTextView = rootView.findViewById(R.id.volumeTextView); this.volumeTextView = rootView.findViewById(R.id.volumeTextView);
this.brightnessTextView = rootView.findViewById(R.id.brightnessTextView); this.brightnessTextView = rootView.findViewById(R.id.brightnessTextView);
this.repeatButton = rootView.findViewById(R.id.repeatButton); this.repeatButton = rootView.findViewById(R.id.repeatButton);
this.queueButton = rootView.findViewById(R.id.queueButton);
this.screenRotationButton = rootView.findViewById(R.id.screenRotationButton); this.screenRotationButton = rootView.findViewById(R.id.screenRotationButton);
this.playPauseButton = rootView.findViewById(R.id.playPauseButton); this.playPauseButton = rootView.findViewById(R.id.playPauseButton);
@ -244,11 +261,22 @@ public final class MainVideoPlayer extends Activity {
gestureDetector.setIsLongpressEnabled(false); gestureDetector.setIsLongpressEnabled(false);
getRootView().setOnTouchListener(listener); getRootView().setOnTouchListener(listener);
queueButton.setOnClickListener(this);
repeatButton.setOnClickListener(this); repeatButton.setOnClickListener(this);
playPauseButton.setOnClickListener(this); playPauseButton.setOnClickListener(this);
screenRotationButton.setOnClickListener(this); screenRotationButton.setOnClickListener(this);
} }
@Override
public int getPreferredResolution() {
if (sharedPreferences == null || context == null) return Integer.MAX_VALUE;
return Localization.resolutionOf(sharedPreferences.getString(
context.getString(R.string.default_resolution_key),
context.getString(R.string.default_resolution_value)
));
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// ExoPlayer Video Listener // ExoPlayer Video Listener
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -310,9 +338,19 @@ public final class MainVideoPlayer extends Activity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
super.onClick(v); super.onClick(v);
if (v.getId() == repeatButton.getId()) onRepeatClicked(); if (v.getId() == repeatButton.getId()) {
else if (v.getId() == playPauseButton.getId()) onVideoPlayPause(); onRepeatClicked();
else if (v.getId() == screenRotationButton.getId()) onScreenRotationClicked();
} else if (v.getId() == playPauseButton.getId()) {
onVideoPlayPause();
} else if (v.getId() == screenRotationButton.getId()) {
onScreenRotationClicked();
} else if (v.getId() == queueButton.getId()) {
onQueueClicked();
return;
}
if (getCurrentState() != STATE_COMPLETED) { if (getCurrentState() != STATE_COMPLETED) {
getControlsVisibilityHandler().removeCallbacksAndMessages(null); getControlsVisibilityHandler().removeCallbacksAndMessages(null);
@ -327,6 +365,19 @@ public final class MainVideoPlayer extends Activity {
} }
} }
private void onQueueClicked() {
queueVisible = true;
buildQueue();
hideSystemUi();
getControlsRoot().setVisibility(View.INVISIBLE);
queueLayout.setVisibility(View.VISIBLE);
}
private void onQueueClosed() {
queueLayout.setVisibility(View.GONE);
queueVisible = false;
}
private void onScreenRotationClicked() { private void onScreenRotationClicked() {
if (DEBUG) Log.d(TAG, "onScreenRotationClicked() called"); if (DEBUG) Log.d(TAG, "onScreenRotationClicked() called");
toggleOrientation(); toggleOrientation();
@ -434,6 +485,20 @@ public final class MainVideoPlayer extends Activity {
// Utils // Utils
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override
public void showControlsThenHide() {
if (queueVisible) return;
super.showControlsThenHide();
}
@Override
public void showControls(long duration) {
if (queueVisible) return;
super.showControls(duration);
}
@Override @Override
public void hideControls(final long duration, long delay) { public void hideControls(final long duration, long delay) {
if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]"); if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
@ -451,6 +516,85 @@ public final class MainVideoPlayer extends Activity {
}, delay); }, delay);
} }
private void buildQueue() {
queueLayout = findViewById(R.id.play_queue_control);
itemsListCloseButton = findViewById(R.id.play_queue_close_area);
itemsList = findViewById(R.id.play_queue);
itemsList.setAdapter(playQueueAdapter);
itemsList.setClickable(true);
itemsList.setLongClickable(true);
itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
itemTouchHelper.attachToRecyclerView(itemsList);
playQueueAdapter.setSelectedListener(getOnSelectedListener());
itemsListCloseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onQueueClosed();
}
});
}
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
if (source.getItemViewType() != target.getItemViewType()) {
return false;
}
final int sourceIndex = source.getLayoutPosition();
final int targetIndex = target.getLayoutPosition();
playQueue.move(sourceIndex, targetIndex);
return true;
}
@Override
public boolean isLongPressDragEnabled() {
return false;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {}
};
}
private PlayQueueItemBuilder.OnSelectedListener getOnSelectedListener() {
return new PlayQueueItemBuilder.OnSelectedListener() {
@Override
public void selected(PlayQueueItem item, View view) {
final int index = playQueue.indexOf(item);
if (index == -1) return;
if (playQueue.getIndex() == index) {
onRestart();
} else {
playQueue.setIndex(index);
}
}
@Override
public void held(PlayQueueItem item, View view) {
final int index = playQueue.indexOf(item);
if (index != -1) playQueue.remove(index);
}
@Override
public void onStartDrag(PlayQueueItemHolder viewHolder) {
if (itemTouchHelper != null) itemTouchHelper.startDrag(viewHolder);
}
};
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Getters // Getters
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////

View File

@ -53,6 +53,7 @@ import android.widget.Toast;
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.trackselection.DefaultTrackSelector;
import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.MainActivity;
@ -73,6 +74,7 @@ import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
@ -405,6 +407,15 @@ public final class PopupVideoPlayer extends Service {
resizingIndicator = rootView.findViewById(R.id.resizing_indicator); resizingIndicator = rootView.findViewById(R.id.resizing_indicator);
} }
@Override
public int getPreferredResolution() {
if (sharedPreferences == null || context == null) return Integer.MAX_VALUE;
return Localization.resolutionOf(sharedPreferences.getString(
context.getString(R.string.default_popup_resolution_key),
context.getString(R.string.default_popup_resolution_value)
));
}
@Override @Override
public void destroy() { public void destroy() {
super.destroy(); super.destroy();
@ -451,6 +462,7 @@ public final class PopupVideoPlayer extends Service {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} }
context.startActivity(intent); context.startActivity(intent);
playerImpl.stopActivityBinding();
destroyPlayer(); destroyPlayer();
stopSelf(); stopSelf();
} }

View File

@ -222,13 +222,15 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
super.handleIntent(intent); super.handleIntent(intent);
if (intent == null) return; if (intent == null) return;
final int resolutionTarget = intent.getIntExtra(MAX_RESOLUTION, Integer.MAX_VALUE); final int resolutionTarget = intent.getIntExtra(MAX_RESOLUTION, getPreferredResolution());
trackSelector.setParameters( trackSelector.setParameters(
// Assume video is horizontal // Assume video is horizontal
new DefaultTrackSelector.Parameters().withMaxVideoSize(Integer.MAX_VALUE, resolutionTarget) new DefaultTrackSelector.Parameters().withMaxVideoSize(Integer.MAX_VALUE, resolutionTarget)
); );
} }
public abstract int getPreferredResolution();
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// UI Builders // UI Builders
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -246,7 +248,8 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
} }
private void buildQualityMenu() { private void buildQualityMenu() {
if (qualityPopupMenu == null || videoTrackGroups == null || selectedVideoTrackGroup == null || videoTrackGroups.length != availableStreams.size()) return; if (qualityPopupMenu == null || videoTrackGroups == null || selectedVideoTrackGroup == null
|| availableStreams == null || videoTrackGroups.length != availableStreams.size()) return;
qualityPopupMenu.getMenu().removeGroup(qualityPopupMenuGroupId); qualityPopupMenu.getMenu().removeGroup(qualityPopupMenuGroupId);
trackGroupInfos = new ArrayList<>(); trackGroupInfos = new ArrayList<>();

View File

@ -6,6 +6,7 @@ import android.content.res.Resources;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.PluralsRes; import android.support.annotation.PluralsRes;
import android.support.annotation.StringRes; import android.support.annotation.StringRes;
import android.text.TextUtils;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
@ -151,4 +152,13 @@ public class Localization {
} }
return output; return output;
} }
public static int resolutionOf(final String resolution) {
final String[] candidates = TextUtils.split(resolution, "p");
if (candidates.length > 0 && TextUtils.isDigitsOnly(candidates[0])) {
return Integer.parseInt(candidates[0]);
} else {
return Integer.MAX_VALUE;
}
}
} }

View File

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@android:color/black" android:background="@android:color/black"
android:gravity="center"> android:gravity="center">
@ -41,6 +42,33 @@
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:visibility="visible"/> tools:visibility="visible"/>
<RelativeLayout
android:id="@+id/play_queue_control"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#64000000"
android:visibility="gone"
tools:visibility="visible">
<ImageButton
android:id="@+id/play_queue_close_area"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="?android:selectableItemBackground"
android:src="@drawable/ic_close_white_24dp"
tools:ignore="ContentDescription"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/play_queue"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/play_queue_close_area"
android:scrollbars="vertical"
app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/play_queue_item"/>
</RelativeLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/playbackControlRoot" android:id="@+id/playbackControlRoot"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -139,6 +167,7 @@
android:layout_toLeftOf="@+id/repeatButton" android:layout_toLeftOf="@+id/repeatButton"
android:background="#00ffffff" android:background="#00ffffff"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:padding="8dp" android:padding="8dp"
android:scaleType="fitXY" android:scaleType="fitXY"
android:src="@drawable/ic_screen_rotation_white" android:src="@drawable/ic_screen_rotation_white"
@ -150,14 +179,30 @@
android:layout_height="35dp" android:layout_height="35dp"
android:layout_marginLeft="2dp" android:layout_marginLeft="2dp"
android:layout_marginRight="2dp" android:layout_marginRight="2dp"
android:layout_toLeftOf="@+id/fullScreenButton" android:layout_toLeftOf="@+id/queueButton"
android:background="#00ffffff" android:background="#00ffffff"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:padding="5dp" android:padding="5dp"
android:scaleType="fitXY" android:scaleType="fitXY"
android:src="@drawable/exo_controls_repeat_off" android:src="@drawable/exo_controls_repeat_off"
tools:ignore="ContentDescription,RtlHardcoded"/> tools:ignore="ContentDescription,RtlHardcoded"/>
<ImageButton
android:id="@+id/queueButton"
android:layout_width="30dp"
android:layout_height="35dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_toLeftOf="@+id/fullScreenButton"
android:background="#00ffffff"
android:clickable="true"
android:focusable="true"
android:padding="5dp"
android:scaleType="fitXY"
android:src="@drawable/list"
tools:ignore="ContentDescription,RtlHardcoded"/>
<ImageButton <ImageButton
android:id="@+id/fullScreenButton" android:id="@+id/fullScreenButton"
android:layout_width="35dp" android:layout_width="35dp"
@ -166,6 +211,7 @@
android:layout_marginLeft="4dp" android:layout_marginLeft="4dp"
android:background="#00ffffff" android:background="#00ffffff"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:scaleType="fitXY" android:scaleType="fitXY"
android:src="@drawable/ic_fullscreen_exit_white" android:src="@drawable/ic_fullscreen_exit_white"
tools:ignore="ContentDescription,RtlHardcoded"/> tools:ignore="ContentDescription,RtlHardcoded"/>