-Enable background and popup playlists.

This commit is contained in:
John Zhen M 2017-09-05 17:48:48 -07:00 committed by John Zhen Mo
parent b54d18d888
commit 7d7a6f7ccc
10 changed files with 192 additions and 125 deletions

View File

@ -724,7 +724,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
.getBoolean(activity.getString(R.string.use_external_audio_player_key), false);
if (!useExternalAudioPlayer && android.os.Build.VERSION.SDK_INT >= 16) {
openNormalBackgroundPlayer(audioStream);
openNormalBackgroundPlayer();
} else {
openExternalBackgroundPlayer(audioStream);
}
@ -763,8 +763,8 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
}
private void openNormalBackgroundPlayer(AudioStream audioStream) {
activity.startService(NavigationHelper.getOpenBackgroundPlayerIntent(activity, currentInfo, audioStream));
private void openNormalBackgroundPlayer() {
activity.startService(NavigationHelper.getOpenBackgroundPlayerIntent(activity, currentInfo));
Toast.makeText(activity, R.string.background_player_playing_toast, Toast.LENGTH_SHORT).show();
}

View File

@ -21,7 +21,9 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.player.BackgroundPlayer;
import org.schabi.newpipe.player.MainVideoPlayer;
import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper;
@ -44,6 +46,8 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
private TextView headerStreamCount;
private Button headerPlayAllButton;
private Button headerPopupButton;
private Button headerBackgroundButton;
public static PlaylistFragment getInstance(int serviceId, String url, String name) {
PlaylistFragment instance = new PlaylistFragment();
@ -71,7 +75,10 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
headerUploaderName = headerRootLayout.findViewById(R.id.uploader_name);
headerUploaderAvatar = headerRootLayout.findViewById(R.id.uploader_avatar_view);
headerStreamCount = headerRootLayout.findViewById(R.id.playlist_stream_count);
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_play_all_button);
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_play_popup_button);
headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_play_bg_button);
return headerRootLayout;
}
@ -138,7 +145,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
}
imageLoader.displayImage(result.uploader_avatar_url, headerUploaderAvatar, DISPLAY_AVATAR_OPTIONS);
headerStreamCount.setText(getResources().getQuantityString(R.plurals.videos, (int) result.stream_count));
headerStreamCount.setText(getResources().getQuantityString(R.plurals.videos, (int) result.stream_count, (int) result.stream_count));
if (!result.errors.isEmpty()) {
showSnackBarError(result.errors, UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(result.service_id), result.url, 0);
@ -147,15 +154,28 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
headerPlayAllButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final Intent intent = NavigationHelper.getExternalPlaylistIntent(
activity, MainVideoPlayer.class, currentInfo, infoListAdapter.getItemsList(), 0
);
startActivity(intent);
startActivity(buildPlaylistIntent(MainVideoPlayer.class));
}
});
headerPopupButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
activity.startService(buildPlaylistIntent(PopupVideoPlayer.class));
}
});
headerBackgroundButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
activity.startService(buildPlaylistIntent(BackgroundPlayer.class));
}
});
}
private Intent buildPlaylistIntent(final Class targetClazz) {
return NavigationHelper.getExternalPlaylistIntent(
activity, targetClazz, currentInfo, infoListAdapter.getItemsList(), 0
);
}
@Override
public void handleNextItems(ListExtractor.NextItemsResult result) {

View File

@ -36,6 +36,7 @@ import android.util.Log;
import android.widget.RemoteViews;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.source.MediaSource;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.MainActivity;
@ -43,11 +44,11 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.Serializable;
/**
* Base players joining the common properties
@ -65,9 +66,6 @@ public class BackgroundPlayer extends Service {
public static final String ACTION_FAST_REWIND = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_FAST_REWIND";
public static final String ACTION_FAST_FORWARD = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_FAST_FORWARD";
public static final String AUDIO_STREAM = "video_only_audio_stream";
private AudioStream audioStream;
private BasePlayerImpl basePlayerImpl;
private PowerManager powerManager;
private WifiManager wifiManager;
@ -177,8 +175,8 @@ public class BackgroundPlayer extends Service {
private void setupNotification(RemoteViews remoteViews) {
//if (videoThumbnail != null) remoteViews.setImageViewBitmap(R.id.notificationCover, videoThumbnail);
///else remoteViews.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
remoteViews.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
remoteViews.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName());
// remoteViews.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
// remoteViews.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName());
remoteViews.setOnClickPendingIntent(R.id.notificationPlayPause,
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
@ -340,12 +338,16 @@ public class BackgroundPlayer extends Service {
@Override
public void onFastRewind() {
if (isPlayerBuffering()) return;
playQueue.setIndex(playQueue.getIndex() - 1);
triggerProgressUpdate();
}
@Override
public void onFastForward() {
if (isPlayerBuffering()) return;
playQueue.setIndex(playQueue.getIndex() + 1);
triggerProgressUpdate();
}
@ -376,6 +378,26 @@ public class BackgroundPlayer extends Service {
// Playback Listener
//////////////////////////////////////////////////////////////////////////*/
@Override
public void sync(final StreamInfo info, final int sortedStreamsIndex) {
super.sync(info, sortedStreamsIndex);
basePlayerImpl.setVideoTitle(info.name);
basePlayerImpl.setUploaderName(info.uploader_name);
notRemoteView.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
notRemoteView.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName());
bigNotRemoteView.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
bigNotRemoteView.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName());
updateNotification(-1);
}
@Override
public MediaSource sourceOf(final StreamInfo info, final int sortedStreamsIndex) {
final AudioStream audio = ListHelper.getHighestQualityAudio(info.audio_streams);
return buildMediaSource(audio.url, MediaFormat.getSuffixById(audio.format));
}
@Override
public void shutdown() {
super.shutdown();

View File

@ -35,6 +35,7 @@ import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
@ -249,8 +250,6 @@ public abstract class BasePlayer implements Player.EventListener,
default:
break;
}
initThumbnail();
}
@ -586,8 +585,13 @@ public abstract class BasePlayer implements Player.EventListener,
@Override
public void onPositionDiscontinuity() {
// Refresh the playback if there is a transition to the next video
int newIndex = simpleExoPlayer.getCurrentWindowIndex();
if (playbackManager.getCurrentSourceIndex() != newIndex) playbackManager.refresh(newIndex);
if (DEBUG) Log.d(TAG, "onPositionDiscontinuity() called with: index = [" + newIndex + "]");
if (newIndex == playbackManager.getCurrentSourceIndex() + 1) {
playbackManager.refresh(newIndex);
}
}
/*//////////////////////////////////////////////////////////////////////////
@ -596,6 +600,7 @@ public abstract class BasePlayer implements Player.EventListener,
@Override
public void block() {
if (simpleExoPlayer == null) return;
Log.d(TAG, "Blocking...");
simpleExoPlayer.stop();
@ -605,6 +610,7 @@ public abstract class BasePlayer implements Player.EventListener,
@Override
public void unblock() {
if (simpleExoPlayer == null) return;
Log.d(TAG, "Unblocking...");
if (restoreQueueIndex != playQueue.getIndex()) {
@ -619,25 +625,28 @@ public abstract class BasePlayer implements Player.EventListener,
@Override
public void sync(final StreamInfo info, final int sortedStreamsIndex) {
if (simpleExoPlayer == null) return;
Log.d(TAG, "Syncing...");
videoUrl = info.url;
videoThumbnailUrl = info.thumbnail_url;
videoTitle = info.name;
initThumbnail();
if (simpleExoPlayer.getCurrentWindowIndex() != playbackManager.getCurrentSourceIndex()) {
Log.w(TAG, "Rewinding to correct window");
simpleExoPlayer.seekTo(playbackManager.getCurrentSourceIndex(), 0L);
if (simpleExoPlayer.getCurrentTimeline().getWindowCount() > playbackManager.getCurrentSourceIndex()) {
simpleExoPlayer.seekToDefaultPosition(playbackManager.getCurrentSourceIndex());
} else {
Toast.makeText(context, "Player out of sync", Toast.LENGTH_SHORT).show();
simpleExoPlayer.seekToDefaultPosition();
}
}
simpleExoPlayer.setPlayWhenReady(true);
}
@Override
public MediaSource sourceOf(final StreamInfo info, final int sortedStreamsIndex) {
return null;
}
@Override
public void shutdown() {
Log.d(TAG, "Shutting down...");
@ -888,4 +897,8 @@ public abstract class BasePlayer implements Player.EventListener,
public PlayQueue getPlayQueue() {
return playQueue;
}
public boolean isPlayerBuffering() {
return currentState == STATE_BUFFERING;
}
}

View File

@ -471,6 +471,7 @@ public class MainVideoPlayer extends Activity {
public boolean onDoubleTap(MotionEvent e) {
if (DEBUG) Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY());
//if (!playerImpl.isPlaying()) return false;
if (playerImpl.isPlayerBuffering()) return false;
if (e.getX() > playerImpl.getRootView().getWidth() / 2)
playerImpl.playQueue.setIndex(playerImpl.playQueue.getIndex() + 1);

View File

@ -580,7 +580,8 @@ public class PopupVideoPlayer extends Service {
public boolean onDoubleTap(MotionEvent e) {
if (DEBUG)
Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY());
if (!playerImpl.isPlaying()) return false;
if (!playerImpl.isPlaying() || playerImpl.isPlayerBuffering()) return false;
if (e.getX() > popupWidth / 2) {
//playerImpl.onFastForward();
playerImpl.playQueue.setIndex(playerImpl.playQueue.getIndex() + 1);

View File

@ -274,7 +274,7 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
video = videos.get(sortedStreamsIndex);
}
final MediaSource mediaSource = super.buildMediaSource(video.url, MediaFormat.getSuffixById(video.format));
final MediaSource mediaSource = buildMediaSource(video.url, MediaFormat.getSuffixById(video.format));
if (!video.isVideoOnly) return mediaSource;
final AudioStream audio = ListHelper.getHighestQualityAudio(info.audio_streams);
@ -282,15 +282,6 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
return new MergingMediaSource(mediaSource, new ExtractorMediaSource(audioUri, cacheDataSourceFactory, extractorsFactory, null, null));
}
@Override
public MediaSource buildMediaSource(String url, String overrideExtension) {
MediaSource mediaSource = super.buildMediaSource(url, overrideExtension);
if (!getSelectedVideoStream().isVideoOnly || videoOnlyAudioStream == null) return mediaSource;
Uri audioUri = Uri.parse(videoOnlyAudioStream.url);
return new MergingMediaSource(mediaSource, new ExtractorMediaSource(audioUri, cacheDataSourceFactory, extractorsFactory, null, null));
}
public void buildQualityMenu(PopupMenu popupMenu) {
for (int i = 0; i < videoStreamsList.size(); i++) {
VideoStream videoStream = videoStreamsList.get(i);

View File

@ -28,6 +28,8 @@ public class PlayQueueItem implements Serializable {
private Throwable error;
private transient Single<StreamInfo> stream;
PlayQueueItem(final StreamInfo streamInfo, final int sortedQualityIndex) {
this.title = streamInfo.name;
this.url = streamInfo.url;
@ -80,6 +82,11 @@ public class PlayQueueItem implements Serializable {
@NonNull
public Single<StreamInfo> getStream() {
return stream == null ? stream = getInfo() : stream;
}
@NonNull
private Single<StreamInfo> getInfo() {
final Consumer<Throwable> onError = new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
@ -90,7 +97,6 @@ public class PlayQueueItem implements Serializable {
return ExtractorHelper.getStreamInfo(this.serviceId, this.url, false)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(3)
.doOnError(onError);
}
}

View File

@ -83,25 +83,6 @@ public class NavigationHelper {
.putExtra(SinglePlayQueue.STREAM, info);
}
public static Intent getOpenBackgroundPlayerIntent(Context context, StreamInfo info, AudioStream audioStream) {
return getOpenBackgroundPlayerIntent(context, info);
}
// public static Intent getOpenBackgroundPlayerIntent(Context context, StreamInfo info) {
// return getOpenBackgroundPlayerIntent(context, info, info.audio_streams.get(ListHelper.getDefaultAudioFormat(context, info.audio_streams)));
// }
//
// public static Intent getOpenBackgroundPlayerIntent(Context context, StreamInfo info, AudioStream audioStream) {
// Intent mIntent = new Intent(context, BackgroundPlayer.class)
// .putExtra(BasePlayer.VIDEO_TITLE, info.name)
// .putExtra(BasePlayer.VIDEO_URL, info.url)
// .putExtra(BasePlayer.VIDEO_THUMBNAIL_URL, info.thumbnail_url)
// .putExtra(BasePlayer.CHANNEL_NAME, info.uploader_name)
// .putExtra(BackgroundPlayer.AUDIO_STREAM, audioStream);
// if (info.start_position > 0) mIntent.putExtra(BasePlayer.START_POSITION, info.start_position * 1000L);
// return mIntent;
// }
/*//////////////////////////////////////////////////////////////////////////
// Through FragmentManager
//////////////////////////////////////////////////////////////////////////*/

View File

@ -9,10 +9,87 @@
android:background="?attr/contrast_background_color"
android:paddingBottom="6dp">
<TextView
android:id="@+id/playlist_title_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="6dp"
android:ellipsize="end"
android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="@dimen/playlist_detail_title_text_size"
tools:text="Mix musics #23 title Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsum"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/top_control">
android:layout_below="@+id/playlist_title_view"
android:id="@+id/playlist_meta">
<RelativeLayout
android:id="@+id/uploader_layout"
android:layout_width="wrap_content"
android:layout_height="@dimen/playlist_detail_uploader_layout_height"
android:layout_marginLeft="4dp"
android:layout_marginRight="6dp"
android:layout_marginTop="6dp"
android:layout_toLeftOf="@+id/playlist_stream_count"
android:layout_toStartOf="@+id/playlist_stream_count"
android:background="?attr/selectableItemBackground"
android:gravity="left|center_vertical"
android:padding="2dp"
android:visibility="gone"
tools:ignore="RtlHardcoded"
tools:visibility="visible">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/uploader_avatar_view"
android:layout_width="@dimen/playlist_detail_uploader_image_size"
android:layout_height="@dimen/playlist_detail_uploader_image_size"
android:layout_alignParentLeft="true"
android:layout_margin="1dp"
android:src="@drawable/buddy"
app:civ_border_color="#ffffff"
app:civ_border_width="1dp"/>
<TextView
android:id="@+id/uploader_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="4dp"
android:layout_toRightOf="@+id/uploader_avatar_view"
android:ellipsize="end"
android:gravity="left|center_vertical"
android:maxLines="1"
android:textSize="@dimen/playlist_detail_subtext_size"
tools:ignore="RtlHardcoded"
tools:text="Typical uploader name"/>
</RelativeLayout>
<TextView
android:id="@+id/playlist_stream_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/uploader_layout"
android:layout_alignTop="@+id/uploader_layout"
android:layout_alignParentRight="true"
android:layout_marginRight="6dp"
android:ellipsize="end"
android:gravity="right|center_vertical"
android:maxLines="1"
android:textSize="@dimen/playlist_detail_subtext_size"
tools:ignore="RtlHardcoded"
tools:text="234 videos"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/play_control"
android:layout_below="@+id/playlist_meta">
<Button
android:id="@+id/playlist_play_all_button"
@ -27,78 +104,33 @@
tools:ignore="RtlHardcoded"
tools:visibility="visible"/>
<TextView
android:id="@+id/playlist_title_view"
android:layout_width="match_parent"
<Button
android:id="@+id/playlist_play_bg_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="6dp"
android:layout_gravity="center_vertical|right"
android:layout_marginRight="2dp"
android:layout_toLeftOf="@+id/playlist_play_all_button"
android:layout_toStartOf="@+id/playlist_play_all_button"
android:layout_centerInParent="true"
android:ellipsize="end"
android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="@dimen/playlist_detail_title_text_size"
tools:text="Mix musics #23 title Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsumLorem ipsum"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/uploader_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/playlist_detail_uploader_layout_height"
android:layout_below="@+id/top_control"
android:layout_marginLeft="4dp"
android:layout_marginRight="6dp"
android:layout_marginTop="6dp"
android:layout_toLeftOf="@+id/playlist_stream_count"
android:layout_toStartOf="@+id/playlist_stream_count"
android:background="?attr/selectableItemBackground"
android:gravity="left|center_vertical"
android:padding="2dp"
android:visibility="gone"
tools:ignore="RtlHardcoded"
tools:visibility="visible">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/uploader_avatar_view"
android:layout_width="@dimen/playlist_detail_uploader_image_size"
android:layout_height="@dimen/playlist_detail_uploader_image_size"
android:layout_alignParentLeft="true"
android:layout_margin="1dp"
android:src="@drawable/buddy"
app:civ_border_color="#ffffff"
app:civ_border_width="1dp"/>
<TextView
android:id="@+id/uploader_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="4dp"
android:layout_toRightOf="@+id/uploader_avatar_view"
android:ellipsize="end"
android:gravity="left|center_vertical"
android:maxLines="1"
android:textSize="@dimen/playlist_detail_subtext_size"
android:text="@string/controls_background_title"
android:textSize="@dimen/channel_rss_title_size"
android:theme="@style/RedButton"
tools:ignore="RtlHardcoded"
tools:text="Typical uploader name"/>
</RelativeLayout>
tools:visibility="visible" />
<TextView
android:id="@+id/playlist_stream_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/uploader_layout"
android:layout_alignEnd="@+id/top_control"
android:layout_alignRight="@+id/top_control"
android:layout_alignTop="@+id/uploader_layout"
android:layout_marginRight="6dp"
android:ellipsize="end"
android:gravity="right|center_vertical"
android:maxLines="1"
android:textSize="@dimen/playlist_detail_subtext_size"
tools:ignore="RtlHardcoded"
tools:text="234 videos"/>
<Button
android:id="@+id/playlist_play_popup_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
android:layout_marginRight="2dp"
android:layout_toLeftOf="@+id/playlist_play_bg_button"
android:layout_toStartOf="@+id/playlist_play_bg_button"
android:text="@string/controls_popup_title"
android:textSize="@dimen/channel_rss_title_size"
android:theme="@style/RedButton"
tools:ignore="RtlHardcoded"
tools:visibility="visible" />
</RelativeLayout>
</RelativeLayout>