Avoid out of bounds when setting less media items than in playlist
Issue: androidx/media#86 #minor-release PiperOrigin-RevId: 455182232 (cherry picked from commit 8f844b32fdf4d41d6a5690e57e55d0c383ee7e3e)
This commit is contained in:
parent
039e102552
commit
14aced6304
@ -185,6 +185,9 @@
|
|||||||
`MediaSession.Callback.onSetMediaUri`. The same functionality can be
|
`MediaSession.Callback.onSetMediaUri`. The same functionality can be
|
||||||
achieved by using `MediaController.setMediaItem` and
|
achieved by using `MediaController.setMediaItem` and
|
||||||
`MediaSession.Callback.onAddMediaItems`.
|
`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:
|
* Data sources:
|
||||||
* Rename `DummyDataSource` to `PlaceholderDataSource`.
|
* Rename `DummyDataSource` to `PlaceholderDataSource`.
|
||||||
* Workaround OkHttp interrupt handling.
|
* Workaround OkHttp interrupt handling.
|
||||||
|
@ -828,7 +828,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
Collections.singletonList(mediaItem),
|
Collections.singletonList(mediaItem),
|
||||||
/* startIndex= */ C.INDEX_UNSET,
|
/* startIndex= */ C.INDEX_UNSET,
|
||||||
/* startPositionMs= */ C.TIME_UNSET,
|
/* startPositionMs= */ C.TIME_UNSET,
|
||||||
/* resetToDefaultPosition= */ false);
|
/* resetToDefaultPosition= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -887,7 +887,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
mediaItems,
|
mediaItems,
|
||||||
/* startIndex= */ C.INDEX_UNSET,
|
/* startIndex= */ C.INDEX_UNSET,
|
||||||
/* startPositionMs= */ C.TIME_UNSET,
|
/* startPositionMs= */ C.TIME_UNSET,
|
||||||
/* resetToDefaultPosition= */ false);
|
/* resetToDefaultPosition= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1832,12 +1832,18 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
throw new IllegalSeekPositionException(newTimeline, startIndex, startPositionMs);
|
throw new IllegalSeekPositionException(newTimeline, startIndex, startPositionMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean correctedStartIndex = false;
|
||||||
if (resetToDefaultPosition) {
|
if (resetToDefaultPosition) {
|
||||||
startIndex = newTimeline.getFirstWindowIndex(playerInfo.shuffleModeEnabled);
|
startIndex = newTimeline.getFirstWindowIndex(playerInfo.shuffleModeEnabled);
|
||||||
startPositionMs = C.TIME_UNSET;
|
startPositionMs = C.TIME_UNSET;
|
||||||
} else if (startIndex == C.INDEX_UNSET) {
|
} else if (startIndex == C.INDEX_UNSET) {
|
||||||
startIndex = playerInfo.sessionPositionInfo.positionInfo.mediaItemIndex;
|
startIndex = playerInfo.sessionPositionInfo.positionInfo.mediaItemIndex;
|
||||||
startPositionMs = playerInfo.sessionPositionInfo.positionInfo.positionMs;
|
startPositionMs = playerInfo.sessionPositionInfo.positionInfo.positionMs;
|
||||||
|
if (startIndex >= newTimeline.getWindowCount()) {
|
||||||
|
correctedStartIndex = true;
|
||||||
|
startIndex = newTimeline.getFirstWindowIndex(playerInfo.shuffleModeEnabled);
|
||||||
|
startPositionMs = C.TIME_UNSET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PositionInfo newPositionInfo;
|
PositionInfo newPositionInfo;
|
||||||
SessionPositionInfo newSessionPositionInfo;
|
SessionPositionInfo newSessionPositionInfo;
|
||||||
@ -1905,7 +1911,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
// Mask the playback state.
|
// Mask the playback state.
|
||||||
int maskingPlaybackState = newPlayerInfo.playbackState;
|
int maskingPlaybackState = newPlayerInfo.playbackState;
|
||||||
if (startIndex != C.INDEX_UNSET && newPlayerInfo.playbackState != STATE_IDLE) {
|
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.
|
// Setting an empty timeline or invalid seek transitions to ended.
|
||||||
maskingPlaybackState = STATE_ENDED;
|
maskingPlaybackState = STATE_ENDED;
|
||||||
} else {
|
} else {
|
||||||
|
@ -36,6 +36,7 @@ import android.os.RemoteException;
|
|||||||
import androidx.media3.common.AudioAttributes;
|
import androidx.media3.common.AudioAttributes;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.HeartRating;
|
import androidx.media3.common.HeartRating;
|
||||||
|
import androidx.media3.common.IllegalSeekPositionException;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.MediaLibraryInfo;
|
import androidx.media3.common.MediaLibraryInfo;
|
||||||
import androidx.media3.common.MediaMetadata;
|
import androidx.media3.common.MediaMetadata;
|
||||||
@ -56,6 +57,7 @@ import androidx.media3.test.session.common.TestUtils;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
@ -64,6 +66,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@ -1055,4 +1058,95 @@ public class MediaControllerTest {
|
|||||||
|
|
||||||
assertThat(mediaMetadata).isEqualTo(testMediaMetadata);
|
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();
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user