Prevent concurrent queue modifications from breaking the cast demo app UI

PiperOrigin-RevId: 233577854
This commit is contained in:
aquilescanta 2019-02-12 11:30:54 +00:00 committed by Andrew Lewis
parent 3a5ed6b889
commit 55e6d1d708
2 changed files with 34 additions and 15 deletions

View File

@ -211,6 +211,7 @@ public class MainActivity extends AppCompatActivity
private class QueueItemViewHolder extends RecyclerView.ViewHolder implements OnClickListener { private class QueueItemViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public final TextView textView; public final TextView textView;
public MediaItem item;
public QueueItemViewHolder(TextView textView) { public QueueItemViewHolder(TextView textView) {
super(textView); super(textView);
@ -236,8 +237,9 @@ public class MainActivity extends AppCompatActivity
@Override @Override
public void onBindViewHolder(QueueItemViewHolder holder, int position) { public void onBindViewHolder(QueueItemViewHolder holder, int position) {
holder.item = playerManager.getItem(position);
TextView view = holder.textView; TextView view = holder.textView;
view.setText(playerManager.getItem(position).title); view.setText(holder.item.title);
// TODO: Solve coloring using the theme's ColorStateList. // TODO: Solve coloring using the theme's ColorStateList.
view.setTextColor(ColorUtils.setAlphaComponent(view.getCurrentTextColor(), view.setTextColor(ColorUtils.setAlphaComponent(view.getCurrentTextColor(),
position == playerManager.getCurrentItemIndex() ? 255 : 100)); position == playerManager.getCurrentItemIndex() ? 255 : 100));
@ -278,7 +280,8 @@ public class MainActivity extends AppCompatActivity
@Override @Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition(); int position = viewHolder.getAdapterPosition();
if (playerManager.removeItem(position)) { QueueItemViewHolder queueItemHolder = (QueueItemViewHolder) viewHolder;
if (playerManager.removeItem(queueItemHolder.item)) {
mediaQueueListAdapter.notifyItemRemoved(position); mediaQueueListAdapter.notifyItemRemoved(position);
// Update whichever item took its place, in case it became the new selected item. // Update whichever item took its place, in case it became the new selected item.
mediaQueueListAdapter.notifyItemChanged(position); mediaQueueListAdapter.notifyItemChanged(position);
@ -289,8 +292,9 @@ public class MainActivity extends AppCompatActivity
public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) { public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder); super.clearView(recyclerView, viewHolder);
if (draggingFromPosition != C.INDEX_UNSET) { if (draggingFromPosition != C.INDEX_UNSET) {
QueueItemViewHolder queueItemHolder = (QueueItemViewHolder) viewHolder;
// A drag has ended. We reflect the media queue change in the player. // A drag has ended. We reflect the media queue change in the player.
if (!playerManager.moveItem(draggingFromPosition, draggingToPosition)) { if (!playerManager.moveItem(queueItemHolder.item, draggingToPosition)) {
// The move failed. The entire sequence of onMove calls since the drag started needs to be // The move failed. The entire sequence of onMove calls since the drag started needs to be
// invalidated. // invalidated.
mediaQueueListAdapter.notifyDataSetChanged(); mediaQueueListAdapter.notifyDataSetChanged();

View File

@ -168,10 +168,16 @@ import java.util.ArrayList;
/** /**
* Removes the item at the given index from the media queue. * Removes the item at the given index from the media queue.
* *
* @param itemIndex The index of the item to remove. * @param item The item to remove.
* @return Whether the removal was successful. * @return Whether the removal was successful.
*/ */
public boolean removeItem(int itemIndex) { public boolean removeItem(MediaItem item) {
int itemIndex = mediaQueue.indexOf(item);
if (itemIndex == -1) {
// This may happen if another sender app removes items while this sender app is in "swiping
// an item" state.
return false;
}
concatenatingMediaSource.removeMediaSource(itemIndex); concatenatingMediaSource.removeMediaSource(itemIndex);
mediaQueue.remove(itemIndex); mediaQueue.remove(itemIndex);
if (currentPlayer == exoCastPlayer) { if (currentPlayer == exoCastPlayer) {
@ -188,20 +194,29 @@ import java.util.ArrayList;
/** /**
* Moves an item within the queue. * Moves an item within the queue.
* *
* @param fromIndex The index of the item to move. * @param item The item to move. This method does nothing if {@code item} is not contained in the
* @param toIndex The target index of the item in the queue. * queue.
* @return Whether the item move was successful. * @param toIndex The target index of the item in the queue. If {@code toIndex} exceeds the last
* position in the queue, {@code toIndex} is clamped to match the largest possible value.
* @return True if {@code item} was contained in the queue, and {@code toIndex} was a valid
* position. False otherwise.
*/ */
public boolean moveItem(int fromIndex, int toIndex) { public boolean moveItem(MediaItem item, int toIndex) {
mediaQueue.add(toIndex, mediaQueue.remove(fromIndex)); int indexOfItem = mediaQueue.indexOf(item);
concatenatingMediaSource.moveMediaSource(fromIndex, toIndex); if (indexOfItem == -1) {
if (currentPlayer == exoCastPlayer) { // This may happen if another sender app removes items while this sender app is in "dragging
exoCastPlayer.moveItemInQueue(fromIndex, toIndex); // an item" state.
return false;
}
int clampedToIndex = Math.min(toIndex, mediaQueue.size() - 1);
mediaQueue.add(clampedToIndex, mediaQueue.remove(indexOfItem));
concatenatingMediaSource.moveMediaSource(indexOfItem, clampedToIndex);
if (currentPlayer == exoCastPlayer) {
exoCastPlayer.moveItemInQueue(indexOfItem, clampedToIndex);
} }
// Index update. // Index update.
maybeSetCurrentItemAndNotify(currentPlayer.getCurrentWindowIndex()); maybeSetCurrentItemAndNotify(currentPlayer.getCurrentWindowIndex());
return true; return clampedToIndex == toIndex;
} }
// Miscellaneous methods. // Miscellaneous methods.