2017-10-13 03:22:25 +02:00
|
|
|
package org.schabi.newpipe.player;
|
|
|
|
|
|
|
|
import android.content.ComponentName;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.content.ServiceConnection;
|
|
|
|
import android.os.Build;
|
|
|
|
import android.os.Bundle;
|
|
|
|
import android.os.IBinder;
|
|
|
|
import android.provider.Settings;
|
|
|
|
import android.support.v7.app.AppCompatActivity;
|
|
|
|
import android.support.v7.widget.LinearLayoutManager;
|
|
|
|
import android.support.v7.widget.RecyclerView;
|
|
|
|
import android.support.v7.widget.Toolbar;
|
|
|
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.Menu;
|
|
|
|
import android.view.MenuItem;
|
|
|
|
import android.view.View;
|
|
|
|
import android.widget.ImageButton;
|
2017-10-27 04:59:25 +02:00
|
|
|
import android.widget.LinearLayout;
|
2017-10-13 03:22:25 +02:00
|
|
|
import android.widget.PopupMenu;
|
|
|
|
import android.widget.ProgressBar;
|
|
|
|
import android.widget.SeekBar;
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
|
|
|
import com.google.android.exoplayer2.PlaybackParameters;
|
|
|
|
import com.google.android.exoplayer2.Player;
|
|
|
|
|
|
|
|
import org.schabi.newpipe.R;
|
|
|
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
2017-11-04 04:32:10 +01:00
|
|
|
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
2018-01-22 04:32:49 +01:00
|
|
|
import org.schabi.newpipe.fragments.local.PlaylistAppendDialog;
|
2017-10-13 03:22:25 +02:00
|
|
|
import org.schabi.newpipe.player.event.PlayerEventListener;
|
|
|
|
import org.schabi.newpipe.playlist.PlayQueueItem;
|
|
|
|
import org.schabi.newpipe.playlist.PlayQueueItemBuilder;
|
|
|
|
import org.schabi.newpipe.playlist.PlayQueueItemHolder;
|
|
|
|
import org.schabi.newpipe.util.Localization;
|
|
|
|
import org.schabi.newpipe.util.NavigationHelper;
|
|
|
|
import org.schabi.newpipe.util.ThemeHelper;
|
|
|
|
|
2017-10-28 19:08:01 +02:00
|
|
|
import static org.schabi.newpipe.player.helper.PlayerHelper.formatPitch;
|
|
|
|
import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed;
|
2017-10-27 04:59:25 +02:00
|
|
|
|
2017-10-13 03:22:25 +02:00
|
|
|
public abstract class ServicePlayerActivity extends AppCompatActivity
|
|
|
|
implements PlayerEventListener, SeekBar.OnSeekBarChangeListener, View.OnClickListener {
|
|
|
|
|
|
|
|
private boolean serviceBound;
|
|
|
|
private ServiceConnection serviceConnection;
|
|
|
|
|
|
|
|
protected BasePlayer player;
|
|
|
|
|
|
|
|
private boolean seeking;
|
2017-10-28 19:08:01 +02:00
|
|
|
private boolean redraw;
|
2017-10-13 03:22:25 +02:00
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Views
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
private static final int RECYCLER_ITEM_POPUP_MENU_GROUP_ID = 47;
|
|
|
|
private static final int PLAYBACK_SPEED_POPUP_MENU_GROUP_ID = 61;
|
|
|
|
private static final int PLAYBACK_PITCH_POPUP_MENU_GROUP_ID = 97;
|
|
|
|
|
2017-11-04 04:32:10 +01:00
|
|
|
private static final int SMOOTH_SCROLL_MAXIMUM_DISTANCE = 80;
|
|
|
|
|
2017-10-13 03:22:25 +02:00
|
|
|
private View rootView;
|
|
|
|
|
|
|
|
private RecyclerView itemsList;
|
|
|
|
private ItemTouchHelper itemTouchHelper;
|
|
|
|
|
2017-10-27 04:59:25 +02:00
|
|
|
private LinearLayout metadata;
|
2017-10-13 03:22:25 +02:00
|
|
|
private TextView metadataTitle;
|
|
|
|
private TextView metadataArtist;
|
|
|
|
|
|
|
|
private SeekBar progressSeekBar;
|
|
|
|
private TextView progressCurrentTime;
|
|
|
|
private TextView progressEndTime;
|
2017-10-27 04:59:25 +02:00
|
|
|
private TextView seekDisplay;
|
2017-10-13 03:22:25 +02:00
|
|
|
|
|
|
|
private ImageButton repeatButton;
|
|
|
|
private ImageButton backwardButton;
|
|
|
|
private ImageButton playPauseButton;
|
|
|
|
private ImageButton forwardButton;
|
|
|
|
private ImageButton shuffleButton;
|
|
|
|
private ProgressBar progressBar;
|
|
|
|
|
|
|
|
private TextView playbackSpeedButton;
|
|
|
|
private PopupMenu playbackSpeedPopupMenu;
|
|
|
|
private TextView playbackPitchButton;
|
|
|
|
private PopupMenu playbackPitchPopupMenu;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Abstracts
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
public abstract String getTag();
|
|
|
|
|
|
|
|
public abstract String getSupportActionTitle();
|
|
|
|
|
|
|
|
public abstract Intent getBindIntent();
|
|
|
|
|
|
|
|
public abstract void startPlayerListener();
|
|
|
|
|
|
|
|
public abstract void stopPlayerListener();
|
|
|
|
|
2018-01-04 07:53:31 +01:00
|
|
|
public abstract int getPlayerOptionMenuResource();
|
|
|
|
|
|
|
|
public abstract boolean onPlayerOptionSelected(MenuItem item);
|
|
|
|
|
|
|
|
public abstract Intent getPlayerShutdownIntent();
|
2017-10-13 03:22:25 +02:00
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Activity Lifecycle
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
ThemeHelper.setTheme(this);
|
|
|
|
setContentView(R.layout.activity_player_queue_control);
|
|
|
|
rootView = findViewById(R.id.main_content);
|
|
|
|
|
|
|
|
final Toolbar toolbar = rootView.findViewById(R.id.toolbar);
|
|
|
|
setSupportActionBar(toolbar);
|
|
|
|
if (getSupportActionBar() != null) {
|
|
|
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
|
|
getSupportActionBar().setTitle(getSupportActionTitle());
|
|
|
|
}
|
|
|
|
|
|
|
|
serviceConnection = getServiceConnection();
|
|
|
|
bind();
|
|
|
|
}
|
|
|
|
|
2017-10-28 19:08:01 +02:00
|
|
|
@Override
|
|
|
|
protected void onResume() {
|
|
|
|
super.onResume();
|
|
|
|
if (redraw) {
|
|
|
|
recreate();
|
|
|
|
redraw = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-13 03:22:25 +02:00
|
|
|
@Override
|
|
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
|
|
getMenuInflater().inflate(R.menu.menu_play_queue, menu);
|
2018-01-04 07:53:31 +01:00
|
|
|
getMenuInflater().inflate(getPlayerOptionMenuResource(), menu);
|
2017-10-13 03:22:25 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
|
|
switch (item.getItemId()) {
|
|
|
|
case android.R.id.home:
|
|
|
|
finish();
|
|
|
|
return true;
|
2018-01-22 04:32:49 +01:00
|
|
|
case R.id.action_append_playlist:
|
|
|
|
appendToPlaylist();
|
2017-10-13 03:22:25 +02:00
|
|
|
return true;
|
|
|
|
case R.id.action_settings:
|
|
|
|
NavigationHelper.openSettings(this);
|
2017-10-28 19:08:01 +02:00
|
|
|
redraw = true;
|
2017-10-13 03:22:25 +02:00
|
|
|
return true;
|
|
|
|
case R.id.action_system_audio:
|
|
|
|
startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS));
|
|
|
|
return true;
|
2018-01-04 07:53:31 +01:00
|
|
|
case R.id.action_switch_main:
|
|
|
|
this.player.setRecovery();
|
|
|
|
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
|
|
|
|
getApplicationContext().startActivity(getSwitchIntent(MainVideoPlayer.class));
|
|
|
|
return true;
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
2018-01-04 07:53:31 +01:00
|
|
|
return onPlayerOptionSelected(item) || super.onOptionsItemSelected(item);
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onDestroy() {
|
|
|
|
super.onDestroy();
|
|
|
|
unbind();
|
|
|
|
}
|
|
|
|
|
2018-01-04 07:53:31 +01:00
|
|
|
protected Intent getSwitchIntent(final Class clazz) {
|
|
|
|
return NavigationHelper.getPlayerIntent(
|
|
|
|
getApplicationContext(),
|
|
|
|
clazz,
|
|
|
|
this.player.getPlayQueue(),
|
|
|
|
this.player.getRepeatMode(),
|
|
|
|
this.player.getPlaybackSpeed(),
|
|
|
|
this.player.getPlaybackPitch(),
|
|
|
|
null
|
2018-01-27 03:55:28 +01:00
|
|
|
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
2018-01-04 07:53:31 +01:00
|
|
|
}
|
2018-01-22 04:32:49 +01:00
|
|
|
|
|
|
|
private void appendToPlaylist() {
|
|
|
|
if (this.player != null && this.player.getPlayQueue() != null) {
|
|
|
|
PlaylistAppendDialog.fromPlayQueueItems(this.player.getPlayQueue().getStreams())
|
|
|
|
.show(getSupportFragmentManager(), getTag());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-13 03:22:25 +02:00
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Service Connection
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
private void bind() {
|
|
|
|
final boolean success = bindService(getBindIntent(), serviceConnection, BIND_AUTO_CREATE);
|
|
|
|
if (!success) {
|
|
|
|
unbindService(serviceConnection);
|
|
|
|
}
|
|
|
|
serviceBound = success;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void unbind() {
|
|
|
|
if(serviceBound) {
|
|
|
|
unbindService(serviceConnection);
|
|
|
|
serviceBound = false;
|
|
|
|
stopPlayerListener();
|
|
|
|
player = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private ServiceConnection getServiceConnection() {
|
|
|
|
return new ServiceConnection() {
|
|
|
|
@Override
|
|
|
|
public void onServiceDisconnected(ComponentName name) {
|
|
|
|
Log.d(getTag(), "Player service is disconnected");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
|
|
|
Log.d(getTag(), "Player service is connected");
|
2017-10-26 22:42:50 +02:00
|
|
|
|
|
|
|
if (service instanceof PlayerServiceBinder) {
|
|
|
|
player = ((PlayerServiceBinder) service).getPlayerInstance();
|
|
|
|
}
|
|
|
|
|
2017-10-27 04:59:25 +02:00
|
|
|
if (player == null || player.getPlayQueue() == null ||
|
|
|
|
player.getPlayQueueAdapter() == null || player.getPlayer() == null) {
|
2017-10-13 03:22:25 +02:00
|
|
|
unbind();
|
2017-10-23 03:58:01 +02:00
|
|
|
finish();
|
2017-10-13 03:22:25 +02:00
|
|
|
} else {
|
|
|
|
buildComponents();
|
|
|
|
startPlayerListener();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Component Building
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
private void buildComponents() {
|
|
|
|
buildQueue();
|
|
|
|
buildMetadata();
|
|
|
|
buildSeekBar();
|
|
|
|
buildControls();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void buildQueue() {
|
|
|
|
itemsList = findViewById(R.id.play_queue);
|
|
|
|
itemsList.setLayoutManager(new LinearLayoutManager(this));
|
2017-10-27 04:59:25 +02:00
|
|
|
itemsList.setAdapter(player.getPlayQueueAdapter());
|
2017-10-13 03:22:25 +02:00
|
|
|
itemsList.setClickable(true);
|
|
|
|
itemsList.setLongClickable(true);
|
2017-11-04 04:32:10 +01:00
|
|
|
itemsList.clearOnScrollListeners();
|
|
|
|
itemsList.addOnScrollListener(getQueueScrollListener());
|
2017-10-13 03:22:25 +02:00
|
|
|
|
|
|
|
itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
|
|
|
|
itemTouchHelper.attachToRecyclerView(itemsList);
|
|
|
|
|
2017-10-27 04:59:25 +02:00
|
|
|
player.getPlayQueueAdapter().setSelectedListener(getOnSelectedListener());
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void buildMetadata() {
|
2017-10-27 04:59:25 +02:00
|
|
|
metadata = rootView.findViewById(R.id.metadata);
|
2017-10-13 03:22:25 +02:00
|
|
|
metadataTitle = rootView.findViewById(R.id.song_name);
|
|
|
|
metadataArtist = rootView.findViewById(R.id.artist_name);
|
2017-10-27 04:59:25 +02:00
|
|
|
|
|
|
|
metadata.setOnClickListener(this);
|
2017-10-28 19:08:01 +02:00
|
|
|
metadataTitle.setSelected(true);
|
|
|
|
metadataArtist.setSelected(true);
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void buildSeekBar() {
|
|
|
|
progressCurrentTime = rootView.findViewById(R.id.current_time);
|
|
|
|
progressSeekBar = rootView.findViewById(R.id.seek_bar);
|
|
|
|
progressEndTime = rootView.findViewById(R.id.end_time);
|
2017-10-27 04:59:25 +02:00
|
|
|
seekDisplay = rootView.findViewById(R.id.seek_display);
|
2017-10-13 03:22:25 +02:00
|
|
|
|
|
|
|
progressSeekBar.setOnSeekBarChangeListener(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void buildControls() {
|
|
|
|
repeatButton = rootView.findViewById(R.id.control_repeat);
|
|
|
|
backwardButton = rootView.findViewById(R.id.control_backward);
|
|
|
|
playPauseButton = rootView.findViewById(R.id.control_play_pause);
|
|
|
|
forwardButton = rootView.findViewById(R.id.control_forward);
|
|
|
|
shuffleButton = rootView.findViewById(R.id.control_shuffle);
|
|
|
|
playbackSpeedButton = rootView.findViewById(R.id.control_playback_speed);
|
|
|
|
playbackPitchButton = rootView.findViewById(R.id.control_playback_pitch);
|
|
|
|
progressBar = rootView.findViewById(R.id.control_progress_bar);
|
|
|
|
|
|
|
|
repeatButton.setOnClickListener(this);
|
|
|
|
backwardButton.setOnClickListener(this);
|
|
|
|
playPauseButton.setOnClickListener(this);
|
|
|
|
forwardButton.setOnClickListener(this);
|
|
|
|
shuffleButton.setOnClickListener(this);
|
|
|
|
playbackSpeedButton.setOnClickListener(this);
|
|
|
|
playbackPitchButton.setOnClickListener(this);
|
|
|
|
|
|
|
|
playbackSpeedPopupMenu = new PopupMenu(this, playbackSpeedButton);
|
|
|
|
playbackPitchPopupMenu = new PopupMenu(this, playbackPitchButton);
|
|
|
|
buildPlaybackSpeedMenu();
|
|
|
|
buildPlaybackPitchMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void buildPlaybackSpeedMenu() {
|
|
|
|
if (playbackSpeedPopupMenu == null) return;
|
|
|
|
|
|
|
|
playbackSpeedPopupMenu.getMenu().removeGroup(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID);
|
|
|
|
for (int i = 0; i < BasePlayer.PLAYBACK_SPEEDS.length; i++) {
|
|
|
|
final float playbackSpeed = BasePlayer.PLAYBACK_SPEEDS[i];
|
2017-10-27 04:59:25 +02:00
|
|
|
final String formattedSpeed = formatSpeed(playbackSpeed);
|
2017-10-13 03:22:25 +02:00
|
|
|
final MenuItem item = playbackSpeedPopupMenu.getMenu().add(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedSpeed);
|
2018-01-04 07:53:31 +01:00
|
|
|
item.setOnMenuItemClickListener(menuItem -> {
|
|
|
|
if (player == null) return false;
|
2017-11-01 01:07:12 +01:00
|
|
|
|
2018-01-04 07:53:31 +01:00
|
|
|
player.setPlaybackSpeed(playbackSpeed);
|
|
|
|
return true;
|
2017-10-13 03:22:25 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void buildPlaybackPitchMenu() {
|
|
|
|
if (playbackPitchPopupMenu == null) return;
|
|
|
|
|
|
|
|
playbackPitchPopupMenu.getMenu().removeGroup(PLAYBACK_PITCH_POPUP_MENU_GROUP_ID);
|
|
|
|
for (int i = 0; i < BasePlayer.PLAYBACK_PITCHES.length; i++) {
|
|
|
|
final float playbackPitch = BasePlayer.PLAYBACK_PITCHES[i];
|
2017-10-27 04:59:25 +02:00
|
|
|
final String formattedPitch = formatPitch(playbackPitch);
|
2017-10-13 03:22:25 +02:00
|
|
|
final MenuItem item = playbackPitchPopupMenu.getMenu().add(PLAYBACK_PITCH_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedPitch);
|
2018-01-04 07:53:31 +01:00
|
|
|
item.setOnMenuItemClickListener(menuItem -> {
|
|
|
|
if (player == null) return false;
|
2017-11-01 01:07:12 +01:00
|
|
|
|
2018-01-04 07:53:31 +01:00
|
|
|
player.setPlaybackPitch(playbackPitch);
|
|
|
|
return true;
|
2017-10-13 03:22:25 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void buildItemPopupMenu(final PlayQueueItem item, final View view) {
|
|
|
|
final PopupMenu menu = new PopupMenu(this, view);
|
|
|
|
final MenuItem remove = menu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 0, Menu.NONE, R.string.play_queue_remove);
|
2018-01-04 07:53:31 +01:00
|
|
|
remove.setOnMenuItemClickListener(menuItem -> {
|
|
|
|
if (player == null) return false;
|
2017-11-01 01:07:12 +01:00
|
|
|
|
2018-01-04 07:53:31 +01:00
|
|
|
final int index = player.getPlayQueue().indexOf(item);
|
|
|
|
if (index != -1) player.getPlayQueue().remove(index);
|
|
|
|
return true;
|
2017-10-13 03:22:25 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
final MenuItem detail = menu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 1, Menu.NONE, R.string.play_queue_stream_detail);
|
2018-01-04 07:53:31 +01:00
|
|
|
detail.setOnMenuItemClickListener(menuItem -> {
|
|
|
|
onOpenDetail(item.getServiceId(), item.getUrl(), item.getTitle());
|
|
|
|
return true;
|
2017-10-13 03:22:25 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
menu.show();
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Component Helpers
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2017-11-04 04:32:10 +01:00
|
|
|
private OnScrollBelowItemsListener getQueueScrollListener() {
|
|
|
|
return new OnScrollBelowItemsListener() {
|
|
|
|
@Override
|
|
|
|
public void onScrolledDown(RecyclerView recyclerView) {
|
|
|
|
if (player != null && player.getPlayQueue() != null && !player.getPlayQueue().isComplete()) {
|
|
|
|
player.getPlayQueue().fetch();
|
|
|
|
} else if (itemsList != null) {
|
|
|
|
itemsList.clearOnScrollListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-10-13 03:22:25 +02:00
|
|
|
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();
|
2017-11-01 01:07:12 +01:00
|
|
|
if (player != null) player.getPlayQueue().move(sourceIndex, targetIndex);
|
2017-10-13 03:22:25 +02:00
|
|
|
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) {
|
2017-11-01 01:07:12 +01:00
|
|
|
if (player != null) player.onSelected(item);
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void held(PlayQueueItem item, View view) {
|
2017-11-01 01:07:12 +01:00
|
|
|
if (player == null) return;
|
|
|
|
|
2017-10-27 04:59:25 +02:00
|
|
|
final int index = player.getPlayQueue().indexOf(item);
|
2017-10-13 03:22:25 +02:00
|
|
|
if (index != -1) buildItemPopupMenu(item, view);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onStartDrag(PlayQueueItemHolder viewHolder) {
|
|
|
|
if (itemTouchHelper != null) itemTouchHelper.startDrag(viewHolder);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onOpenDetail(int serviceId, String videoUrl, String videoTitle) {
|
|
|
|
NavigationHelper.openVideoDetail(this, serviceId, videoUrl, videoTitle);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void scrollToSelected() {
|
2017-11-04 04:32:10 +01:00
|
|
|
if (player == null) return;
|
|
|
|
|
|
|
|
final int currentPlayingIndex = player.getPlayQueue().getIndex();
|
|
|
|
final int currentVisibleIndex;
|
|
|
|
if (itemsList.getLayoutManager() instanceof LinearLayoutManager) {
|
|
|
|
final LinearLayoutManager layout = ((LinearLayoutManager) itemsList.getLayoutManager());
|
|
|
|
currentVisibleIndex = layout.findFirstVisibleItemPosition();
|
|
|
|
} else {
|
|
|
|
currentVisibleIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
final int distance = Math.abs(currentPlayingIndex - currentVisibleIndex);
|
|
|
|
if (distance < SMOOTH_SCROLL_MAXIMUM_DISTANCE) {
|
|
|
|
itemsList.smoothScrollToPosition(currentPlayingIndex);
|
|
|
|
} else {
|
|
|
|
itemsList.scrollToPosition(currentPlayingIndex);
|
|
|
|
}
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Component On-Click Listener
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onClick(View view) {
|
2017-11-11 23:47:34 +01:00
|
|
|
if (player == null) return;
|
|
|
|
|
2017-10-13 03:22:25 +02:00
|
|
|
if (view.getId() == repeatButton.getId()) {
|
2017-11-11 23:47:34 +01:00
|
|
|
player.onRepeatClicked();
|
2017-10-13 03:22:25 +02:00
|
|
|
|
|
|
|
} else if (view.getId() == backwardButton.getId()) {
|
2017-11-11 23:47:34 +01:00
|
|
|
player.onPlayPrevious();
|
2017-10-13 03:22:25 +02:00
|
|
|
|
|
|
|
} else if (view.getId() == playPauseButton.getId()) {
|
2017-11-11 23:47:34 +01:00
|
|
|
player.onVideoPlayPause();
|
2017-10-13 03:22:25 +02:00
|
|
|
|
|
|
|
} else if (view.getId() == forwardButton.getId()) {
|
2017-11-11 23:47:34 +01:00
|
|
|
player.onPlayNext();
|
2017-10-13 03:22:25 +02:00
|
|
|
|
|
|
|
} else if (view.getId() == shuffleButton.getId()) {
|
2017-11-11 23:47:34 +01:00
|
|
|
player.onShuffleClicked();
|
2017-10-13 03:22:25 +02:00
|
|
|
|
|
|
|
} else if (view.getId() == playbackSpeedButton.getId()) {
|
|
|
|
playbackSpeedPopupMenu.show();
|
|
|
|
|
|
|
|
} else if (view.getId() == playbackPitchButton.getId()) {
|
|
|
|
playbackPitchPopupMenu.show();
|
2017-10-27 04:59:25 +02:00
|
|
|
|
|
|
|
} else if (view.getId() == metadata.getId()) {
|
|
|
|
scrollToSelected();
|
|
|
|
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Seekbar Listener
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
2017-10-27 04:59:25 +02:00
|
|
|
if (fromUser) {
|
|
|
|
final String seekTime = Localization.getDurationString(progress / 1000);
|
|
|
|
progressCurrentTime.setText(seekTime);
|
|
|
|
seekDisplay.setText(seekTime);
|
|
|
|
}
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
|
|
|
seeking = true;
|
2017-10-27 04:59:25 +02:00
|
|
|
seekDisplay.setVisibility(View.VISIBLE);
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
2017-11-01 01:07:12 +01:00
|
|
|
if (player != null) player.simpleExoPlayer.seekTo(seekBar.getProgress());
|
2017-10-27 04:59:25 +02:00
|
|
|
seekDisplay.setVisibility(View.GONE);
|
2017-10-13 03:22:25 +02:00
|
|
|
seeking = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Binding Service Listener
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters) {
|
|
|
|
onStateChanged(state);
|
|
|
|
onPlayModeChanged(repeatMode, shuffled);
|
|
|
|
onPlaybackParameterChanged(parameters);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onProgressUpdate(int currentProgress, int duration, int bufferPercent) {
|
|
|
|
// Set buffer progress
|
|
|
|
progressSeekBar.setSecondaryProgress((int) (progressSeekBar.getMax() * ((float) bufferPercent / 100)));
|
|
|
|
|
|
|
|
// Set Duration
|
|
|
|
progressSeekBar.setMax(duration);
|
|
|
|
progressEndTime.setText(Localization.getDurationString(duration / 1000));
|
|
|
|
|
|
|
|
// Set current time if not seeking
|
|
|
|
if (!seeking) {
|
|
|
|
progressSeekBar.setProgress(currentProgress);
|
|
|
|
progressCurrentTime.setText(Localization.getDurationString(currentProgress / 1000));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onMetadataUpdate(StreamInfo info) {
|
|
|
|
if (info != null) {
|
2017-12-08 15:05:08 +01:00
|
|
|
metadataTitle.setText(info.getName());
|
2017-10-13 03:22:25 +02:00
|
|
|
metadataArtist.setText(info.uploader_name);
|
|
|
|
scrollToSelected();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onServiceStopped() {
|
|
|
|
unbind();
|
2017-10-23 03:58:01 +02:00
|
|
|
finish();
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Binding Service Helper
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
private void onStateChanged(final int state) {
|
|
|
|
switch (state) {
|
|
|
|
case BasePlayer.STATE_PAUSED:
|
|
|
|
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
|
|
|
|
break;
|
|
|
|
case BasePlayer.STATE_PLAYING:
|
|
|
|
playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
|
|
|
break;
|
|
|
|
case BasePlayer.STATE_COMPLETED:
|
|
|
|
playPauseButton.setImageResource(R.drawable.ic_replay_white);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case BasePlayer.STATE_PAUSED:
|
|
|
|
case BasePlayer.STATE_PLAYING:
|
|
|
|
case BasePlayer.STATE_COMPLETED:
|
|
|
|
playPauseButton.setClickable(true);
|
|
|
|
playPauseButton.setVisibility(View.VISIBLE);
|
|
|
|
progressBar.setVisibility(View.GONE);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
playPauseButton.setClickable(false);
|
|
|
|
playPauseButton.setVisibility(View.INVISIBLE);
|
|
|
|
progressBar.setVisibility(View.VISIBLE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onPlayModeChanged(final int repeatMode, final boolean shuffled) {
|
|
|
|
switch (repeatMode) {
|
|
|
|
case Player.REPEAT_MODE_OFF:
|
|
|
|
repeatButton.setImageResource(R.drawable.exo_controls_repeat_off);
|
|
|
|
break;
|
|
|
|
case Player.REPEAT_MODE_ONE:
|
|
|
|
repeatButton.setImageResource(R.drawable.exo_controls_repeat_one);
|
|
|
|
break;
|
|
|
|
case Player.REPEAT_MODE_ALL:
|
|
|
|
repeatButton.setImageResource(R.drawable.exo_controls_repeat_all);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
final int shuffleAlpha = shuffled ? 255 : 77;
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
|
|
|
shuffleButton.setImageAlpha(shuffleAlpha);
|
|
|
|
} else {
|
|
|
|
shuffleButton.setAlpha(shuffleAlpha);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onPlaybackParameterChanged(final PlaybackParameters parameters) {
|
|
|
|
if (parameters != null) {
|
2017-10-27 04:59:25 +02:00
|
|
|
playbackSpeedButton.setText(formatSpeed(parameters.speed));
|
|
|
|
playbackPitchButton.setText(formatPitch(parameters.pitch));
|
2017-10-13 03:22:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|