Skip to content

Commit

Permalink
Avoid out of bounds when setting less media items than in playlist
Browse files Browse the repository at this point in the history
Issue: #86
#minor-release
PiperOrigin-RevId: 455182232
(cherry picked from commit 8f844b3)
  • Loading branch information
marcbaechinger committed Jun 15, 2022
1 parent 039e102 commit 14aced6
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 3 deletions.
3 changes: 3 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@
`MediaSession.Callback.onSetMediaUri`. The same functionality can be
achieved by using `MediaController.setMediaItem` and
`MediaSession.Callback.onAddMediaItems`.
* Fix `IndexOutOfBoundsException` when setting less media items than in
the current playlist
([#86](https://github.com/androidx/media/issues/86)).
* Data sources:
* Rename `DummyDataSource` to `PlaceholderDataSource`.
* Workaround OkHttp interrupt handling.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,7 @@ public void setMediaItem(MediaItem mediaItem) {
Collections.singletonList(mediaItem),
/* startIndex= */ C.INDEX_UNSET,
/* startPositionMs= */ C.TIME_UNSET,
/* resetToDefaultPosition= */ false);
/* resetToDefaultPosition= */ true);
}

@Override
Expand Down Expand Up @@ -887,7 +887,7 @@ public void setMediaItems(List<MediaItem> mediaItems) {
mediaItems,
/* startIndex= */ C.INDEX_UNSET,
/* startPositionMs= */ C.TIME_UNSET,
/* resetToDefaultPosition= */ false);
/* resetToDefaultPosition= */ true);
}

@Override
Expand Down Expand Up @@ -1832,12 +1832,18 @@ private void setMediaItemsInternal(
throw new IllegalSeekPositionException(newTimeline, startIndex, startPositionMs);
}

boolean correctedStartIndex = false;
if (resetToDefaultPosition) {
startIndex = newTimeline.getFirstWindowIndex(playerInfo.shuffleModeEnabled);
startPositionMs = C.TIME_UNSET;
} else if (startIndex == C.INDEX_UNSET) {
startIndex = playerInfo.sessionPositionInfo.positionInfo.mediaItemIndex;
startPositionMs = playerInfo.sessionPositionInfo.positionInfo.positionMs;
if (startIndex >= newTimeline.getWindowCount()) {
correctedStartIndex = true;
startIndex = newTimeline.getFirstWindowIndex(playerInfo.shuffleModeEnabled);
startPositionMs = C.TIME_UNSET;
}
}
PositionInfo newPositionInfo;
SessionPositionInfo newSessionPositionInfo;
Expand Down Expand Up @@ -1905,7 +1911,7 @@ private void setMediaItemsInternal(
// Mask the playback state.
int maskingPlaybackState = newPlayerInfo.playbackState;
if (startIndex != C.INDEX_UNSET && newPlayerInfo.playbackState != STATE_IDLE) {
if (newTimeline.isEmpty() || startIndex >= newTimeline.getWindowCount()) {
if (newTimeline.isEmpty() || correctedStartIndex) {
// Setting an empty timeline or invalid seek transitions to ended.
maskingPlaybackState = STATE_ENDED;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C;
import androidx.media3.common.HeartRating;
import androidx.media3.common.IllegalSeekPositionException;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaLibraryInfo;
import androidx.media3.common.MediaMetadata;
Expand All @@ -56,6 +57,7 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
Expand All @@ -64,6 +66,7 @@
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
Expand Down Expand Up @@ -1055,4 +1058,95 @@ public void getMediaMetadata() throws Exception {

assertThat(mediaMetadata).isEqualTo(testMediaMetadata);
}

@Test
public void
setMediaItems_setLessMediaItemsThanCurrentMediaItemIndex_masksCurrentMediaItemIndexAndStateCorrectly()
throws Exception {
MediaController controller = controllerTestRule.createController(remoteSession.getToken());
List<MediaItem> threeItemsList =
ImmutableList.of(
MediaItem.fromUri("http://www.google.com/1"),
MediaItem.fromUri("http://www.google.com/2"),
MediaItem.fromUri("http://www.google.com/3"));
List<MediaItem> twoItemsList =
ImmutableList.of(
MediaItem.fromUri("http://www.google.com/1"),
MediaItem.fromUri("http://www.google.com/2"));

int[] currentMediaIndexAndState =
threadTestRule
.getHandler()
.postAndSync(
() -> {
controller.setMediaItems(threeItemsList);
controller.prepare();
controller.seekTo(/* mediaItemIndex= */ 2, /* positionMs= */ C.TIME_UNSET);
controller.setMediaItems(twoItemsList);
return new int[] {
controller.getCurrentMediaItemIndex(), controller.getPlaybackState()
};
});

assertThat(currentMediaIndexAndState[0]).isEqualTo(0);
assertThat(currentMediaIndexAndState[1]).isEqualTo(Player.STATE_BUFFERING);
}

@Test
public void
setMediaItems_setLessMediaItemsThanCurrentMediaItemIndexResetPositionFalse_masksCurrentMediaItemIndexAndStateCorrectly()
throws Exception {
MediaController controller = controllerTestRule.createController(remoteSession.getToken());
List<MediaItem> threeItemsList =
ImmutableList.of(
MediaItem.fromUri("http://www.google.com/1"),
MediaItem.fromUri("http://www.google.com/2"),
MediaItem.fromUri("http://www.google.com/3"));
List<MediaItem> twoItemsList =
ImmutableList.of(
MediaItem.fromUri("http://www.google.com/1"),
MediaItem.fromUri("http://www.google.com/2"));

int[] currentMediaItemIndexAndState =
threadTestRule
.getHandler()
.postAndSync(
() -> {
controller.setMediaItems(threeItemsList);
controller.prepare();
controller.seekTo(/* mediaItemIndex= */ 2, /* positionMs= */ C.TIME_UNSET);
controller.setMediaItems(twoItemsList, /* resetPosition= */ false);
return new int[] {
controller.getCurrentMediaItemIndex(), controller.getPlaybackState()
};
});

assertThat(currentMediaItemIndexAndState[0]).isEqualTo(0);
assertThat(currentMediaItemIndexAndState[1]).isEqualTo(Player.STATE_ENDED);
}

@Test
public void setMediaItems_startIndexTooLarge_throwIllegalSeekPositionException()
throws Exception {
MediaController controller = controllerTestRule.createController(remoteSession.getToken());
List<MediaItem> threeItemsList =
ImmutableList.of(
MediaItem.fromUri("http://www.google.com/1"),
MediaItem.fromUri("http://www.google.com/2"),
MediaItem.fromUri("http://www.google.com/3"));

Assert.assertThrows(
IllegalSeekPositionException.class,
() ->
threadTestRule
.getHandler()
.postAndSync(
() -> {
controller.setMediaItems(
threeItemsList,
/* startIndex= */ 99,
/* startPositionMs= */ C.TIME_UNSET);
return controller.getCurrentMediaItemIndex();
}));
}
}

0 comments on commit 14aced6

Please sign in to comment.