-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) {
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);
@ -785,7 +776,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
if (append) {
intent = NavigationHelper.getPlayerIntent(activity, PopupVideoPlayer.class, playQueue, true);
} 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);
}
@ -853,7 +844,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
// ExoPlayer
final PlayQueue playQueue = new SinglePlayQueue(currentInfo);
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 {
// Internal Player
mIntent = new Intent(activity, PlayVideoActivity.class)

View File

@ -28,6 +28,9 @@ import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
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.view.GestureDetector;
import android.view.MotionEvent;
@ -35,6 +38,7 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.PopupMenu;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
@ -45,7 +49,10 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.stream.StreamInfo;
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.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ThemeHelper;
@ -159,6 +166,7 @@ public final class MainVideoPlayer extends Activity {
private void showSystemUi() {
if (DEBUG) Log.d(TAG, "showSystemUi() called");
if (playerImpl != null && playerImpl.queueVisible) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
@ -212,10 +220,18 @@ public final class MainVideoPlayer extends Activity {
private TextView volumeTextView;
private TextView brightnessTextView;
private ImageButton repeatButton;
private ImageButton queueButton;
private ImageButton screenRotationButton;
private ImageButton playPauseButton;
private RelativeLayout queueLayout;
private ImageButton itemsListCloseButton;
private RecyclerView itemsList;
private ItemTouchHelper itemTouchHelper;
private boolean queueVisible;
VideoPlayerImpl() {
super("VideoPlayerImpl" + MainVideoPlayer.TAG, MainVideoPlayer.this);
}
@ -228,6 +244,7 @@ public final class MainVideoPlayer extends Activity {
this.volumeTextView = rootView.findViewById(R.id.volumeTextView);
this.brightnessTextView = rootView.findViewById(R.id.brightnessTextView);
this.repeatButton = rootView.findViewById(R.id.repeatButton);
this.queueButton = rootView.findViewById(R.id.queueButton);
this.screenRotationButton = rootView.findViewById(R.id.screenRotationButton);
this.playPauseButton = rootView.findViewById(R.id.playPauseButton);
@ -244,11 +261,22 @@ public final class MainVideoPlayer extends Activity {
gestureDetector.setIsLongpressEnabled(false);
getRootView().setOnTouchListener(listener);
queueButton.setOnClickListener(this);
repeatButton.setOnClickListener(this);
playPauseButton.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
//////////////////////////////////////////////////////////////////////////*/
@ -310,9 +338,19 @@ public final class MainVideoPlayer extends Activity {
@Override
public void onClick(View v) {
super.onClick(v);
if (v.getId() == repeatButton.getId()) onRepeatClicked();
else if (v.getId() == playPauseButton.getId()) onVideoPlayPause();
else if (v.getId() == screenRotationButton.getId()) onScreenRotationClicked();
if (v.getId() == repeatButton.getId()) {
onRepeatClicked();
} 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) {
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() {
if (DEBUG) Log.d(TAG, "onScreenRotationClicked() called");
toggleOrientation();
@ -434,6 +485,20 @@ public final class MainVideoPlayer extends Activity {
// Utils
//////////////////////////////////////////////////////////////////////////*/
@Override
public void showControlsThenHide() {
if (queueVisible) return;
super.showControlsThenHide();
}
@Override
public void showControls(long duration) {
if (queueVisible) return;
super.showControls(duration);
}
@Override
public void hideControls(final long duration, long delay) {
if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
@ -451,6 +516,85 @@ public final class MainVideoPlayer extends Activity {
}, 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
///////////////////////////////////////////////////////////////////////////

View File

@ -53,6 +53,7 @@ import android.widget.Toast;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import org.schabi.newpipe.BuildConfig;
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.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ThemeHelper;
@ -405,6 +407,15 @@ public final class PopupVideoPlayer extends Service {
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
public void destroy() {
super.destroy();
@ -451,6 +462,7 @@ public final class PopupVideoPlayer extends Service {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
playerImpl.stopActivityBinding();
destroyPlayer();
stopSelf();
}

View File

@ -222,13 +222,15 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
super.handleIntent(intent);
if (intent == null) return;
final int resolutionTarget = intent.getIntExtra(MAX_RESOLUTION, Integer.MAX_VALUE);
final int resolutionTarget = intent.getIntExtra(MAX_RESOLUTION, getPreferredResolution());
trackSelector.setParameters(
// Assume video is horizontal
new DefaultTrackSelector.Parameters().withMaxVideoSize(Integer.MAX_VALUE, resolutionTarget)
);
}
public abstract int getPreferredResolution();
/*//////////////////////////////////////////////////////////////////////////
// UI Builders
//////////////////////////////////////////////////////////////////////////*/
@ -246,7 +248,8 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
}
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);
trackGroupInfos = new ArrayList<>();

View File

@ -6,6 +6,7 @@ import android.content.res.Resources;
import android.preference.PreferenceManager;
import android.support.annotation.PluralsRes;
import android.support.annotation.StringRes;
import android.text.TextUtils;
import org.schabi.newpipe.R;
@ -151,4 +152,13 @@ public class Localization {
}
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"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@android:color/black"
android:gravity="center">
@ -41,6 +42,33 @@
tools:ignore="ContentDescription"
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
android:id="@+id/playbackControlRoot"
android:layout_width="match_parent"
@ -139,6 +167,7 @@
android:layout_toLeftOf="@+id/repeatButton"
android:background="#00ffffff"
android:clickable="true"
android:focusable="true"
android:padding="8dp"
android:scaleType="fitXY"
android:src="@drawable/ic_screen_rotation_white"
@ -150,14 +179,30 @@
android:layout_height="35dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_toLeftOf="@+id/fullScreenButton"
android:layout_toLeftOf="@+id/queueButton"
android:background="#00ffffff"
android:clickable="true"
android:focusable="true"
android:padding="5dp"
android:scaleType="fitXY"
android:src="@drawable/exo_controls_repeat_off"
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
android:id="@+id/fullScreenButton"
android:layout_width="35dp"
@ -166,6 +211,7 @@
android:layout_marginLeft="4dp"
android:background="#00ffffff"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
android:src="@drawable/ic_fullscreen_exit_white"
tools:ignore="ContentDescription,RtlHardcoded"/>