-Added shuffle button to background player.
-Extracted MediaSourceManager window size as parameter. -Removed redundant list manipulation in PlayQueueAdapter.
This commit is contained in:
parent
f1e52b8b92
commit
77979eddde
|
@ -84,7 +84,7 @@ public final class BackgroundPlayer extends Service {
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public interface PlayerEventListener {
|
public interface PlayerEventListener {
|
||||||
void onPlaybackUpdate(int state, int repeatMode, PlaybackParameters parameters);
|
void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters);
|
||||||
void onProgressUpdate(int currentProgress, int duration, int bufferPercent);
|
void onProgressUpdate(int currentProgress, int duration, int bufferPercent);
|
||||||
void onMetadataUpdate(StreamInfo info);
|
void onMetadataUpdate(StreamInfo info);
|
||||||
void onServiceStopped();
|
void onServiceStopped();
|
||||||
|
@ -340,8 +340,9 @@ public final class BackgroundPlayer extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRepeatClicked() {
|
public void onShuffleClicked() {
|
||||||
super.onRepeatClicked();
|
super.onShuffleClicked();
|
||||||
|
updatePlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -491,7 +492,7 @@ public final class BackgroundPlayer extends Service {
|
||||||
|
|
||||||
private void updatePlayback() {
|
private void updatePlayback() {
|
||||||
if (activityListener != null) {
|
if (activityListener != null) {
|
||||||
activityListener.onPlaybackUpdate(currentState, simpleExoPlayer.getRepeatMode(), simpleExoPlayer.getPlaybackParameters());
|
activityListener.onPlaybackUpdate(currentState, simpleExoPlayer.getRepeatMode(), playQueue.isShuffled(), simpleExoPlayer.getPlaybackParameters());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ public class BackgroundPlayerActivity extends AppCompatActivity
|
||||||
private ImageButton backwardButton;
|
private ImageButton backwardButton;
|
||||||
private ImageButton playPauseButton;
|
private ImageButton playPauseButton;
|
||||||
private ImageButton forwardButton;
|
private ImageButton forwardButton;
|
||||||
|
private ImageButton shuffleButton;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Activity Lifecycle
|
// Activity Lifecycle
|
||||||
|
@ -196,11 +197,13 @@ public class BackgroundPlayerActivity extends AppCompatActivity
|
||||||
backwardButton = rootView.findViewById(R.id.control_backward);
|
backwardButton = rootView.findViewById(R.id.control_backward);
|
||||||
playPauseButton = rootView.findViewById(R.id.control_play_pause);
|
playPauseButton = rootView.findViewById(R.id.control_play_pause);
|
||||||
forwardButton = rootView.findViewById(R.id.control_forward);
|
forwardButton = rootView.findViewById(R.id.control_forward);
|
||||||
|
shuffleButton = rootView.findViewById(R.id.control_shuffle);
|
||||||
|
|
||||||
repeatButton.setOnClickListener(this);
|
repeatButton.setOnClickListener(this);
|
||||||
backwardButton.setOnClickListener(this);
|
backwardButton.setOnClickListener(this);
|
||||||
playPauseButton.setOnClickListener(this);
|
playPauseButton.setOnClickListener(this);
|
||||||
forwardButton.setOnClickListener(this);
|
forwardButton.setOnClickListener(this);
|
||||||
|
shuffleButton.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildItemPopupMenu(final PlayQueueItem item, final View view) {
|
private void buildItemPopupMenu(final PlayQueueItem item, final View view) {
|
||||||
|
@ -298,6 +301,10 @@ public class BackgroundPlayerActivity extends AppCompatActivity
|
||||||
context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
|
context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void scrollToSelected() {
|
||||||
|
itemsList.smoothScrollToPosition(player.playQueue.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Component On-Click Listener
|
// Component On-Click Listener
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -308,10 +315,14 @@ public class BackgroundPlayerActivity extends AppCompatActivity
|
||||||
player.onRepeatClicked();
|
player.onRepeatClicked();
|
||||||
} else if (view.getId() == backwardButton.getId()) {
|
} else if (view.getId() == backwardButton.getId()) {
|
||||||
player.onPlayPrevious();
|
player.onPlayPrevious();
|
||||||
|
scrollToSelected();
|
||||||
} else if (view.getId() == playPauseButton.getId()) {
|
} else if (view.getId() == playPauseButton.getId()) {
|
||||||
player.onVideoPlayPause();
|
player.onVideoPlayPause();
|
||||||
|
scrollToSelected();
|
||||||
} else if (view.getId() == forwardButton.getId()) {
|
} else if (view.getId() == forwardButton.getId()) {
|
||||||
player.onPlayNext();
|
player.onPlayNext();
|
||||||
|
} else if (view.getId() == shuffleButton.getId()) {
|
||||||
|
player.onShuffleClicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +351,7 @@ public class BackgroundPlayerActivity extends AppCompatActivity
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackUpdate(int state, int repeatMode, PlaybackParameters parameters) {
|
public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case BasePlayer.STATE_PAUSED:
|
case BasePlayer.STATE_PAUSED:
|
||||||
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
|
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
|
||||||
|
@ -355,29 +366,41 @@ public class BackgroundPlayerActivity extends AppCompatActivity
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int alpha = 255;
|
int repeatAlpha = 255;
|
||||||
switch (repeatMode) {
|
switch (repeatMode) {
|
||||||
case Player.REPEAT_MODE_OFF:
|
case Player.REPEAT_MODE_OFF:
|
||||||
alpha = 77;
|
repeatAlpha = 77;
|
||||||
break;
|
break;
|
||||||
case Player.REPEAT_MODE_ONE:
|
case Player.REPEAT_MODE_ONE:
|
||||||
// todo change image
|
// todo change image
|
||||||
alpha = 168;
|
repeatAlpha = 168;
|
||||||
break;
|
break;
|
||||||
case Player.REPEAT_MODE_ALL:
|
case Player.REPEAT_MODE_ALL:
|
||||||
alpha = 255;
|
repeatAlpha = 255;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
repeatButton.setImageAlpha(alpha);
|
repeatButton.setImageAlpha(repeatAlpha);
|
||||||
} else {
|
} else {
|
||||||
repeatButton.setAlpha(alpha);
|
repeatButton.setAlpha(repeatAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
int shuffleAlpha = 255;
|
||||||
|
if (!shuffled) {
|
||||||
|
shuffleAlpha = 77;
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
|
shuffleButton.setImageAlpha(shuffleAlpha);
|
||||||
|
} else {
|
||||||
|
shuffleButton.setAlpha(shuffleAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameters != null) {
|
if (parameters != null) {
|
||||||
final float speed = parameters.speed;
|
final float speed = parameters.speed;
|
||||||
final float pitch = parameters.pitch;
|
final float pitch = parameters.pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scrollToSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -401,6 +424,7 @@ public class BackgroundPlayerActivity extends AppCompatActivity
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
metadataTitle.setText(info.name);
|
metadataTitle.setText(info.name);
|
||||||
metadataArtist.setText(info.uploader_name);
|
metadataArtist.setText(info.uploader_name);
|
||||||
|
scrollToSelected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -535,7 +535,7 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Repeat
|
// Repeat and shuffle
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public void onRepeatClicked() {
|
public void onRepeatClicked() {
|
||||||
|
@ -560,6 +560,18 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||||
if (DEBUG) Log.d(TAG, "onRepeatClicked() currentRepeatMode = " + simpleExoPlayer.getRepeatMode());
|
if (DEBUG) Log.d(TAG, "onRepeatClicked() currentRepeatMode = " + simpleExoPlayer.getRepeatMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onShuffleClicked() {
|
||||||
|
if (DEBUG) Log.d(TAG, "onShuffleClicked() called");
|
||||||
|
|
||||||
|
if (playQueue == null) return;
|
||||||
|
|
||||||
|
if (playQueue.isShuffled()) {
|
||||||
|
playQueue.unshuffle();
|
||||||
|
} else {
|
||||||
|
playQueue.shuffle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// ExoPlayer Listener
|
// ExoPlayer Listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
|
@ -12,13 +12,11 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.player.mediasource.DeferredMediaSource;
|
import org.schabi.newpipe.player.mediasource.DeferredMediaSource;
|
||||||
import org.schabi.newpipe.playlist.PlayQueue;
|
import org.schabi.newpipe.playlist.PlayQueue;
|
||||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||||
import org.schabi.newpipe.playlist.events.ErrorEvent;
|
|
||||||
import org.schabi.newpipe.playlist.events.MoveEvent;
|
import org.schabi.newpipe.playlist.events.MoveEvent;
|
||||||
import org.schabi.newpipe.playlist.events.PlayQueueMessage;
|
import org.schabi.newpipe.playlist.events.PlayQueueMessage;
|
||||||
import org.schabi.newpipe.playlist.events.RemoveEvent;
|
import org.schabi.newpipe.playlist.events.RemoveEvent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
@ -29,10 +27,8 @@ import io.reactivex.functions.Consumer;
|
||||||
public class MediaSourceManager implements DeferredMediaSource.Callback {
|
public class MediaSourceManager implements DeferredMediaSource.Callback {
|
||||||
private final String TAG = "MediaSourceManager@" + Integer.toHexString(hashCode());
|
private final String TAG = "MediaSourceManager@" + Integer.toHexString(hashCode());
|
||||||
// One-side rolling window size for default loading
|
// One-side rolling window size for default loading
|
||||||
// Effectively loads WINDOW_SIZE * 2 + 1 streams, must be greater than 0
|
// Effectively loads windowSize * 2 + 1 streams, must be greater than 0
|
||||||
// todo: inject this parameter, allow user settings perhaps
|
private final int windowSize;
|
||||||
private static final int WINDOW_SIZE = 1;
|
|
||||||
|
|
||||||
private PlaybackListener playbackListener;
|
private PlaybackListener playbackListener;
|
||||||
private PlayQueue playQueue;
|
private PlayQueue playQueue;
|
||||||
|
|
||||||
|
@ -45,8 +41,15 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
|
||||||
|
|
||||||
public MediaSourceManager(@NonNull final PlaybackListener listener,
|
public MediaSourceManager(@NonNull final PlaybackListener listener,
|
||||||
@NonNull final PlayQueue playQueue) {
|
@NonNull final PlayQueue playQueue) {
|
||||||
|
this(listener, playQueue, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MediaSourceManager(@NonNull final PlaybackListener listener,
|
||||||
|
@NonNull final PlayQueue playQueue,
|
||||||
|
final int windowSize) {
|
||||||
this.playbackListener = listener;
|
this.playbackListener = listener;
|
||||||
this.playQueue = playQueue;
|
this.playQueue = playQueue;
|
||||||
|
this.windowSize = windowSize;
|
||||||
|
|
||||||
this.syncReactor = new SerialDisposable();
|
this.syncReactor = new SerialDisposable();
|
||||||
|
|
||||||
|
@ -85,7 +88,7 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the current playing stream and the streams within its WINDOW_SIZE bound.
|
* Loads the current playing stream and the streams within its windowSize bound.
|
||||||
*
|
*
|
||||||
* Unblocks the player once the item at the current index is loaded.
|
* Unblocks the player once the item at the current index is loaded.
|
||||||
* */
|
* */
|
||||||
|
@ -97,8 +100,8 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
|
||||||
load(currentItem);
|
load(currentItem);
|
||||||
|
|
||||||
// The rest are just for seamless playback
|
// The rest are just for seamless playback
|
||||||
final int leftBound = Math.max(0, currentIndex - WINDOW_SIZE);
|
final int leftBound = Math.max(0, currentIndex - windowSize);
|
||||||
final int rightLimit = currentIndex + WINDOW_SIZE + 1;
|
final int rightLimit = currentIndex + windowSize + 1;
|
||||||
final int rightBound = Math.min(playQueue.size(), rightLimit);
|
final int rightBound = Math.min(playQueue.size(), rightLimit);
|
||||||
final List<PlayQueueItem> items = new ArrayList<>(playQueue.getStreams().subList(leftBound, rightBound));
|
final List<PlayQueueItem> items = new ArrayList<>(playQueue.getStreams().subList(leftBound, rightBound));
|
||||||
|
|
||||||
|
@ -119,6 +122,10 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
|
||||||
populateSources();
|
populateSources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getWindowSize() {
|
||||||
|
return windowSize;
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Event Reactor
|
// Event Reactor
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -188,7 +195,7 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private boolean isPlayQueueReady() {
|
private boolean isPlayQueueReady() {
|
||||||
return playQueue.isComplete() || playQueue.size() - playQueue.getIndex() > WINDOW_SIZE;
|
return playQueue.isComplete() || playQueue.size() - playQueue.getIndex() > windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean tryBlock() {
|
private boolean tryBlock() {
|
||||||
|
|
|
@ -222,6 +222,8 @@ public abstract class PlayQueue implements Serializable {
|
||||||
* */
|
* */
|
||||||
public synchronized void append(final PlayQueueItem... items) {
|
public synchronized void append(final PlayQueueItem... items) {
|
||||||
streams.addAll(Arrays.asList(items));
|
streams.addAll(Arrays.asList(items));
|
||||||
|
if (backup != null) backup.addAll(Arrays.asList(items));
|
||||||
|
|
||||||
broadcast(new AppendEvent(items.length));
|
broadcast(new AppendEvent(items.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +234,8 @@ public abstract class PlayQueue implements Serializable {
|
||||||
* */
|
* */
|
||||||
public synchronized void append(final Collection<PlayQueueItem> items) {
|
public synchronized void append(final Collection<PlayQueueItem> items) {
|
||||||
streams.addAll(items);
|
streams.addAll(items);
|
||||||
|
if (backup != null) backup.addAll(items);
|
||||||
|
|
||||||
broadcast(new AppendEvent(items.size()));
|
broadcast(new AppendEvent(items.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,6 +275,10 @@ public abstract class PlayQueue implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
streams.remove(index);
|
streams.remove(index);
|
||||||
|
if (backup != null) {
|
||||||
|
final int backupIndex = backup.indexOf(getItem(index));
|
||||||
|
backup.remove(backupIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void move(final int source, final int target) {
|
public synchronized void move(final int source, final int target) {
|
||||||
|
@ -300,7 +308,9 @@ public abstract class PlayQueue implements Serializable {
|
||||||
* Will emit a {@link ReorderEvent} in any context.
|
* Will emit a {@link ReorderEvent} in any context.
|
||||||
* */
|
* */
|
||||||
public synchronized void shuffle() {
|
public synchronized void shuffle() {
|
||||||
|
if (backup == null) {
|
||||||
backup = new ArrayList<>(streams);
|
backup = new ArrayList<>(streams);
|
||||||
|
}
|
||||||
final PlayQueueItem current = getItem();
|
final PlayQueueItem current = getItem();
|
||||||
Collections.shuffle(streams);
|
Collections.shuffle(streams);
|
||||||
queueIndex.set(streams.indexOf(current));
|
queueIndex.set(streams.indexOf(current));
|
||||||
|
|
|
@ -72,18 +72,6 @@ public class PlayQueueAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
||||||
playQueueItemBuilder.setOnSelectedListener(listener);
|
playQueueItemBuilder.setOnSelectedListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(final List<PlayQueueItem> data) {
|
|
||||||
playQueue.append(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(final PlayQueueItem... data) {
|
|
||||||
playQueue.append(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(final int index) {
|
|
||||||
playQueue.remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startReactor() {
|
private void startReactor() {
|
||||||
final Observer<PlayQueueMessage> observer = new Observer<PlayQueueMessage>() {
|
final Observer<PlayQueueMessage> observer = new Observer<PlayQueueMessage>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -126,23 +126,22 @@
|
||||||
android:id="@+id/control_repeat"
|
android:id="@+id/control_repeat"
|
||||||
android:layout_width="25dp"
|
android:layout_width="25dp"
|
||||||
android:layout_height="25dp"
|
android:layout_height="25dp"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_toLeftOf="@+id/control_backward"
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="5dp"
|
||||||
android:background="#00000000"
|
android:background="#00000000"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitXY"
|
||||||
android:src="@drawable/ic_repeat_white"
|
android:src="@drawable/ic_repeat_white"
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/control_backward"
|
android:id="@+id/control_backward"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_marginRight="5dp"
|
android:layout_marginLeft="5dp"
|
||||||
android:layout_toLeftOf="@+id/control_play_pause"
|
android:layout_toLeftOf="@+id/control_play_pause"
|
||||||
android:background="#00000000"
|
android:background="#00000000"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
|
@ -157,8 +156,10 @@
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
android:layout_marginRight="5dp"
|
android:layout_marginRight="5dp"
|
||||||
android:layout_toLeftOf="@+id/control_forward"
|
|
||||||
android:background="#00000000"
|
android:background="#00000000"
|
||||||
android:padding="2dp"
|
android:padding="2dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
|
@ -171,9 +172,9 @@
|
||||||
android:id="@+id/control_forward"
|
android:id="@+id/control_forward"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_marginRight="8dp"
|
android:layout_marginRight="5dp"
|
||||||
|
android:layout_toRightOf="@+id/control_play_pause"
|
||||||
android:background="#00000000"
|
android:background="#00000000"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
|
@ -181,6 +182,20 @@
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/ic_action_av_fast_forward"
|
android:src="@drawable/ic_action_av_fast_forward"
|
||||||
tools:ignore="ContentDescription"/>
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/control_shuffle"
|
||||||
|
android:layout_width="25dp"
|
||||||
|
android:layout_height="25dp"
|
||||||
|
android:layout_toRightOf="@+id/control_forward"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginRight="5dp"
|
||||||
|
android:background="#00000000"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_palette_white_24dp"
|
||||||
|
tools:ignore="ContentDescription"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
Loading…
Reference in New Issue