Add missing null and Bundle checks in MediaSession/ControllerStub
PiperOrigin-RevId: 599477547
This commit is contained in:
parent
616cb943f0
commit
59dc5b6692
@ -1466,7 +1466,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
|||||||
* playback, in microseconds.
|
* playback, in microseconds.
|
||||||
*
|
*
|
||||||
* <p>The default position must be less or equal to the {@linkplain #setDurationUs duration},
|
* <p>The default position must be less or equal to the {@linkplain #setDurationUs duration},
|
||||||
* is set.
|
* if set.
|
||||||
*
|
*
|
||||||
* @param defaultPositionUs The default position relative to the start of the media item at
|
* @param defaultPositionUs The default position relative to the start of the media item at
|
||||||
* which to begin playback, in microseconds.
|
* which to begin playback, in microseconds.
|
||||||
|
@ -1970,6 +1970,13 @@ public class MediaController implements Player {
|
|||||||
connectionCallback.onAccepted();
|
connectionCallback.onAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the binder object used to connect to the session. */
|
||||||
|
@Nullable
|
||||||
|
@VisibleForTesting(otherwise = NONE)
|
||||||
|
/* package */ final IMediaController getBinder() {
|
||||||
|
return impl.getBinder();
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyApplicationThread() {
|
private void verifyApplicationThread() {
|
||||||
checkState(Looper.myLooper() == getApplicationLooper(), WRONG_THREAD_ERROR_MESSAGE);
|
checkState(Looper.myLooper() == getApplicationLooper(), WRONG_THREAD_ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
@ -2215,5 +2222,8 @@ public class MediaController implements Player {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
MediaBrowserCompat getBrowserCompat();
|
MediaBrowserCompat getBrowserCompat();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
IMediaController getBinder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1929,6 +1929,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IMediaController getBinder() {
|
||||||
|
return controllerStub;
|
||||||
|
}
|
||||||
|
|
||||||
private static Timeline createMaskingTimeline(List<Window> windows, List<Period> periods) {
|
private static Timeline createMaskingTimeline(List<Window> windows, List<Period> periods) {
|
||||||
return new RemotableTimeline(
|
return new RemotableTimeline(
|
||||||
new ImmutableList.Builder<Window>().addAll(windows).build(),
|
new ImmutableList.Builder<Window>().addAll(windows).build(),
|
||||||
|
@ -1316,6 +1316,12 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization;
|
|||||||
return browserCompat;
|
return browserCompat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IMediaController getBinder() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
void onConnected() {
|
void onConnected() {
|
||||||
if (released || connected) {
|
if (released || connected) {
|
||||||
return;
|
return;
|
||||||
|
@ -47,7 +47,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSessionResult(int sequenceNum, Bundle sessionResultBundle) {
|
public void onSessionResult(int sequenceNum, @Nullable Bundle sessionResultBundle) {
|
||||||
|
if (sessionResultBundle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SessionResult result;
|
SessionResult result;
|
||||||
try {
|
try {
|
||||||
result = SessionResult.fromBundle(sessionResultBundle);
|
result = SessionResult.fromBundle(sessionResultBundle);
|
||||||
@ -62,7 +65,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLibraryResult(int sequenceNum, Bundle libraryResultBundle) {
|
public void onLibraryResult(int sequenceNum, @Nullable Bundle libraryResultBundle) {
|
||||||
|
if (libraryResultBundle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
LibraryResult<?> result;
|
LibraryResult<?> result;
|
||||||
try {
|
try {
|
||||||
result = LibraryResult.fromUnknownBundle(libraryResultBundle);
|
result = LibraryResult.fromUnknownBundle(libraryResultBundle);
|
||||||
@ -77,7 +83,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnected(int seq, Bundle connectionResultBundle) {
|
public void onConnected(int seq, @Nullable Bundle connectionResultBundle) {
|
||||||
|
if (connectionResultBundle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ConnectionState connectionState;
|
ConnectionState connectionState;
|
||||||
try {
|
try {
|
||||||
connectionState = ConnectionState.fromBundle(connectionResultBundle);
|
connectionState = ConnectionState.fromBundle(connectionResultBundle);
|
||||||
@ -97,7 +106,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetCustomLayout(int seq, List<Bundle> commandButtonBundleList) {
|
public void onSetCustomLayout(int seq, @Nullable List<Bundle> commandButtonBundleList) {
|
||||||
|
if (commandButtonBundleList == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
List<CommandButton> layout;
|
List<CommandButton> layout;
|
||||||
try {
|
try {
|
||||||
layout =
|
layout =
|
||||||
@ -111,7 +123,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAvailableCommandsChangedFromSession(
|
public void onAvailableCommandsChangedFromSession(
|
||||||
int seq, Bundle sessionCommandsBundle, Bundle playerCommandsBundle) {
|
int seq, @Nullable Bundle sessionCommandsBundle, @Nullable Bundle playerCommandsBundle) {
|
||||||
|
if (sessionCommandsBundle == null || playerCommandsBundle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SessionCommands sessionCommands;
|
SessionCommands sessionCommands;
|
||||||
try {
|
try {
|
||||||
sessionCommands = SessionCommands.fromBundle(sessionCommandsBundle);
|
sessionCommands = SessionCommands.fromBundle(sessionCommandsBundle);
|
||||||
@ -132,7 +147,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAvailableCommandsChangedFromPlayer(int seq, Bundle commandsBundle) {
|
public void onAvailableCommandsChangedFromPlayer(int seq, @Nullable Bundle commandsBundle) {
|
||||||
|
if (commandsBundle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Commands commandsFromPlayer;
|
Commands commandsFromPlayer;
|
||||||
try {
|
try {
|
||||||
commandsFromPlayer = Commands.fromBundle(commandsBundle);
|
commandsFromPlayer = Commands.fromBundle(commandsBundle);
|
||||||
@ -145,8 +163,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCustomCommand(int seq, Bundle commandBundle, Bundle args) {
|
public void onCustomCommand(int seq, @Nullable Bundle commandBundle, @Nullable Bundle args) {
|
||||||
if (args == null) {
|
if (commandBundle == null || args == null) {
|
||||||
Log.w(TAG, "Ignoring custom command with null args.");
|
Log.w(TAG, "Ignoring custom command with null args.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -161,14 +179,22 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSessionActivityChanged(int seq, PendingIntent sessionActivity)
|
public void onSessionActivityChanged(int seq, @Nullable PendingIntent sessionActivity)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
|
if (sessionActivity == null) {
|
||||||
|
Log.w(TAG, "Ignoring null session activity intent");
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchControllerTaskOnHandler(
|
dispatchControllerTaskOnHandler(
|
||||||
controller -> controller.onSetSessionActivity(seq, sessionActivity));
|
controller -> controller.onSetSessionActivity(seq, sessionActivity));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPeriodicSessionPositionInfoChanged(int seq, Bundle sessionPositionInfoBundle) {
|
public void onPeriodicSessionPositionInfoChanged(
|
||||||
|
int seq, @Nullable Bundle sessionPositionInfoBundle) {
|
||||||
|
if (sessionPositionInfoBundle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SessionPositionInfo sessionPositionInfo;
|
SessionPositionInfo sessionPositionInfo;
|
||||||
try {
|
try {
|
||||||
sessionPositionInfo = SessionPositionInfo.fromBundle(sessionPositionInfoBundle);
|
sessionPositionInfo = SessionPositionInfo.fromBundle(sessionPositionInfoBundle);
|
||||||
@ -185,7 +211,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void onPlayerInfoChanged(int seq, Bundle playerInfoBundle, boolean isTimelineExcluded) {
|
public void onPlayerInfoChanged(
|
||||||
|
int seq, @Nullable Bundle playerInfoBundle, boolean isTimelineExcluded) {
|
||||||
onPlayerInfoChangedWithExclusions(
|
onPlayerInfoChangedWithExclusions(
|
||||||
seq,
|
seq,
|
||||||
playerInfoBundle,
|
playerInfoBundle,
|
||||||
@ -196,7 +223,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
/** Added in {@link #VERSION_INT} 2. */
|
/** Added in {@link #VERSION_INT} 2. */
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerInfoChangedWithExclusions(
|
public void onPlayerInfoChangedWithExclusions(
|
||||||
int seq, Bundle playerInfoBundle, Bundle playerInfoExclusions) {
|
int seq, @Nullable Bundle playerInfoBundle, @Nullable Bundle playerInfoExclusions) {
|
||||||
|
if (playerInfoBundle == null || playerInfoExclusions == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
PlayerInfo playerInfo;
|
PlayerInfo playerInfo;
|
||||||
try {
|
try {
|
||||||
playerInfo = PlayerInfo.fromBundle(playerInfoBundle);
|
playerInfo = PlayerInfo.fromBundle(playerInfoBundle);
|
||||||
@ -216,7 +246,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExtrasChanged(int seq, Bundle extras) {
|
public void onExtrasChanged(int seq, @Nullable Bundle extras) {
|
||||||
|
if (extras == null) {
|
||||||
|
Log.w(TAG, "Ignoring null Bundle for extras");
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchControllerTaskOnHandler(controller -> controller.onExtrasChanged(extras));
|
dispatchControllerTaskOnHandler(controller -> controller.onExtrasChanged(extras));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +264,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@Override
|
@Override
|
||||||
public void onSearchResultChanged(
|
public void onSearchResultChanged(
|
||||||
int seq, String query, int itemCount, @Nullable Bundle libraryParams)
|
int seq, @Nullable String query, int itemCount, @Nullable Bundle libraryParamsBundle)
|
||||||
throws RuntimeException {
|
throws RuntimeException {
|
||||||
if (TextUtils.isEmpty(query)) {
|
if (TextUtils.isEmpty(query)) {
|
||||||
Log.w(TAG, "onSearchResultChanged(): Ignoring empty query");
|
Log.w(TAG, "onSearchResultChanged(): Ignoring empty query");
|
||||||
@ -240,18 +274,22 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
Log.w(TAG, "onSearchResultChanged(): Ignoring negative itemCount: " + itemCount);
|
Log.w(TAG, "onSearchResultChanged(): Ignoring negative itemCount: " + itemCount);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@Nullable LibraryParams libraryParams;
|
||||||
|
try {
|
||||||
|
libraryParams =
|
||||||
|
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for LibraryParams", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchControllerTaskOnHandler(
|
dispatchControllerTaskOnHandler(
|
||||||
(ControllerTask<MediaBrowserImplBase>)
|
(ControllerTask<MediaBrowserImplBase>)
|
||||||
browser ->
|
browser -> browser.notifySearchResultChanged(query, itemCount, libraryParams));
|
||||||
browser.notifySearchResultChanged(
|
|
||||||
query,
|
|
||||||
itemCount,
|
|
||||||
libraryParams == null ? null : LibraryParams.fromBundle(libraryParams)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChildrenChanged(
|
public void onChildrenChanged(
|
||||||
int seq, String parentId, int itemCount, @Nullable Bundle libraryParams) {
|
int seq, @Nullable String parentId, int itemCount, @Nullable Bundle libraryParamsBundle) {
|
||||||
if (TextUtils.isEmpty(parentId)) {
|
if (TextUtils.isEmpty(parentId)) {
|
||||||
Log.w(TAG, "onChildrenChanged(): Ignoring empty parentId");
|
Log.w(TAG, "onChildrenChanged(): Ignoring empty parentId");
|
||||||
return;
|
return;
|
||||||
@ -260,13 +298,17 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
Log.w(TAG, "onChildrenChanged(): Ignoring negative itemCount: " + itemCount);
|
Log.w(TAG, "onChildrenChanged(): Ignoring negative itemCount: " + itemCount);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@Nullable LibraryParams libraryParams;
|
||||||
|
try {
|
||||||
|
libraryParams =
|
||||||
|
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for LibraryParams", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchControllerTaskOnHandler(
|
dispatchControllerTaskOnHandler(
|
||||||
(ControllerTask<MediaBrowserImplBase>)
|
(ControllerTask<MediaBrowserImplBase>)
|
||||||
browser ->
|
browser -> browser.notifyChildrenChanged(parentId, itemCount, libraryParams));
|
||||||
browser.notifyChildrenChanged(
|
|
||||||
parentId,
|
|
||||||
itemCount,
|
|
||||||
libraryParams == null ? null : LibraryParams.fromBundle(libraryParams)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
@ -454,7 +454,10 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("UngroupedOverloads") // Overload belongs to AIDL interface that is separated.
|
@SuppressWarnings("UngroupedOverloads") // Overload belongs to AIDL interface that is separated.
|
||||||
public void connect(IMediaController caller, ControllerInfo controllerInfo) {
|
public void connect(@Nullable IMediaController caller, @Nullable ControllerInfo controllerInfo) {
|
||||||
|
if (caller == null || controllerInfo == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
@Nullable MediaSessionImpl sessionImpl = this.sessionImpl.get();
|
@Nullable MediaSessionImpl sessionImpl = this.sessionImpl.get();
|
||||||
if (sessionImpl == null || sessionImpl.isReleased()) {
|
if (sessionImpl == null || sessionImpl.isReleased()) {
|
||||||
try {
|
try {
|
||||||
@ -507,8 +510,11 @@ import java.util.concurrent.ExecutionException;
|
|||||||
connectionResult.availableSessionCommands,
|
connectionResult.availableSessionCommands,
|
||||||
connectionResult.availablePlayerCommands);
|
connectionResult.availablePlayerCommands);
|
||||||
sequencedFutureManager =
|
sequencedFutureManager =
|
||||||
checkStateNotNull(
|
connectedControllersManager.getSequencedFutureManager(controllerInfo);
|
||||||
connectedControllersManager.getSequencedFutureManager(controllerInfo));
|
if (sequencedFutureManager == null) {
|
||||||
|
Log.w(TAG, "Ignoring connection request from unknown controller info");
|
||||||
|
return;
|
||||||
|
}
|
||||||
// If connection is accepted, notify the current state to the controller.
|
// If connection is accepted, notify the current state to the controller.
|
||||||
// It's needed because we cannot call synchronous calls between
|
// It's needed because we cannot call synchronous calls between
|
||||||
// session/controller.
|
// session/controller.
|
||||||
@ -596,8 +602,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
public void connect(
|
public void connect(
|
||||||
@Nullable IMediaController caller,
|
@Nullable IMediaController caller,
|
||||||
int sequenceNumber,
|
int sequenceNumber,
|
||||||
@Nullable Bundle connectionRequestBundle)
|
@Nullable Bundle connectionRequestBundle) {
|
||||||
throws RuntimeException {
|
|
||||||
if (caller == null || connectionRequestBundle == null) {
|
if (caller == null || connectionRequestBundle == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -633,7 +638,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop(@Nullable IMediaController caller, int sequenceNumber) throws RemoteException {
|
public void stop(@Nullable IMediaController caller, int sequenceNumber) {
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -653,8 +658,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release(@Nullable IMediaController caller, int sequenceNumber)
|
public void release(@Nullable IMediaController caller, int sequenceNumber) {
|
||||||
throws RemoteException {
|
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -700,7 +704,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void play(@Nullable IMediaController caller, int sequenceNumber) throws RuntimeException {
|
public void play(@Nullable IMediaController caller, int sequenceNumber) {
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -727,7 +731,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pause(@Nullable IMediaController caller, int sequenceNumber) throws RuntimeException {
|
public void pause(@Nullable IMediaController caller, int sequenceNumber) {
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -744,8 +748,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepare(@Nullable IMediaController caller, int sequenceNumber)
|
public void prepare(@Nullable IMediaController caller, int sequenceNumber) {
|
||||||
throws RuntimeException {
|
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -754,7 +757,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekToDefaultPosition(IMediaController caller, int sequenceNumber) {
|
public void seekToDefaultPosition(@Nullable IMediaController caller, int sequenceNumber) {
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -767,7 +770,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekToDefaultPositionWithMediaItemIndex(
|
public void seekToDefaultPositionWithMediaItemIndex(
|
||||||
IMediaController caller, int sequenceNumber, int mediaItemIndex) throws RemoteException {
|
@Nullable IMediaController caller, int sequenceNumber, int mediaItemIndex) {
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -782,8 +785,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekTo(@Nullable IMediaController caller, int sequenceNumber, long positionMs)
|
public void seekTo(@Nullable IMediaController caller, int sequenceNumber, long positionMs) {
|
||||||
throws RuntimeException {
|
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -796,8 +798,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekToWithMediaItemIndex(
|
public void seekToWithMediaItemIndex(
|
||||||
IMediaController caller, int sequenceNumber, int mediaItemIndex, long positionMs)
|
@Nullable IMediaController caller, int sequenceNumber, int mediaItemIndex, long positionMs) {
|
||||||
throws RemoteException {
|
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -812,7 +813,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekBack(IMediaController caller, int sequenceNumber) {
|
public void seekBack(@Nullable IMediaController caller, int sequenceNumber) {
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -880,9 +881,9 @@ import java.util.concurrent.ExecutionException;
|
|||||||
public void setRatingWithMediaId(
|
public void setRatingWithMediaId(
|
||||||
@Nullable IMediaController caller,
|
@Nullable IMediaController caller,
|
||||||
int sequenceNumber,
|
int sequenceNumber,
|
||||||
String mediaId,
|
@Nullable String mediaId,
|
||||||
@Nullable Bundle ratingBundle) {
|
@Nullable Bundle ratingBundle) {
|
||||||
if (caller == null || ratingBundle == null) {
|
if (caller == null || mediaId == null || ratingBundle == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (TextUtils.isEmpty(mediaId)) {
|
if (TextUtils.isEmpty(mediaId)) {
|
||||||
@ -941,11 +942,19 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPlaybackParameters(
|
public void setPlaybackParameters(
|
||||||
@Nullable IMediaController caller, int sequenceNumber, Bundle playbackParametersBundle) {
|
@Nullable IMediaController caller,
|
||||||
|
int sequenceNumber,
|
||||||
|
@Nullable Bundle playbackParametersBundle) {
|
||||||
if (caller == null || playbackParametersBundle == null) {
|
if (caller == null || playbackParametersBundle == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PlaybackParameters playbackParameters = PlaybackParameters.fromBundle(playbackParametersBundle);
|
PlaybackParameters playbackParameters;
|
||||||
|
try {
|
||||||
|
playbackParameters = PlaybackParameters.fromBundle(playbackParametersBundle);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for PlaybackParameters", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
queueSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
sequenceNumber,
|
sequenceNumber,
|
||||||
@ -1134,7 +1143,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMediaItem(
|
public void addMediaItem(
|
||||||
@Nullable IMediaController caller, int sequenceNumber, Bundle mediaItemBundle) {
|
@Nullable IMediaController caller, int sequenceNumber, @Nullable Bundle mediaItemBundle) {
|
||||||
if (caller == null || mediaItemBundle == null) {
|
if (caller == null || mediaItemBundle == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1159,7 +1168,10 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMediaItemWithIndex(
|
public void addMediaItemWithIndex(
|
||||||
@Nullable IMediaController caller, int sequenceNumber, int index, Bundle mediaItemBundle) {
|
@Nullable IMediaController caller,
|
||||||
|
int sequenceNumber,
|
||||||
|
int index,
|
||||||
|
@Nullable Bundle mediaItemBundle) {
|
||||||
if (caller == null || mediaItemBundle == null) {
|
if (caller == null || mediaItemBundle == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1317,7 +1329,10 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void replaceMediaItem(
|
public void replaceMediaItem(
|
||||||
IMediaController caller, int sequenceNumber, int index, Bundle mediaItemBundle) {
|
@Nullable IMediaController caller,
|
||||||
|
int sequenceNumber,
|
||||||
|
int index,
|
||||||
|
@Nullable Bundle mediaItemBundle) {
|
||||||
if (caller == null || mediaItemBundle == null) {
|
if (caller == null || mediaItemBundle == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1351,11 +1366,11 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void replaceMediaItems(
|
public void replaceMediaItems(
|
||||||
IMediaController caller,
|
@Nullable IMediaController caller,
|
||||||
int sequenceNumber,
|
int sequenceNumber,
|
||||||
int fromIndex,
|
int fromIndex,
|
||||||
int toIndex,
|
int toIndex,
|
||||||
IBinder mediaItemsRetriever) {
|
@Nullable IBinder mediaItemsRetriever) {
|
||||||
if (caller == null || mediaItemsRetriever == null) {
|
if (caller == null || mediaItemsRetriever == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1606,9 +1621,16 @@ import java.util.concurrent.ExecutionException;
|
|||||||
public void setAudioAttributes(
|
public void setAudioAttributes(
|
||||||
@Nullable IMediaController caller,
|
@Nullable IMediaController caller,
|
||||||
int sequenceNumber,
|
int sequenceNumber,
|
||||||
Bundle audioAttributes,
|
@Nullable Bundle audioAttributes,
|
||||||
boolean handleAudioFocus) {
|
boolean handleAudioFocus) {
|
||||||
if (caller == null) {
|
if (caller == null || audioAttributes == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AudioAttributes attributes;
|
||||||
|
try {
|
||||||
|
attributes = AudioAttributes.fromBundle(audioAttributes);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for AudioAttributes", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
queueSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
@ -1616,9 +1638,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
sequenceNumber,
|
sequenceNumber,
|
||||||
COMMAND_SET_AUDIO_ATTRIBUTES,
|
COMMAND_SET_AUDIO_ATTRIBUTES,
|
||||||
sendSessionResultSuccess(
|
sendSessionResultSuccess(
|
||||||
player ->
|
player -> player.setAudioAttributes(attributes, handleAudioFocus)));
|
||||||
player.setAudioAttributes(
|
|
||||||
AudioAttributes.fromBundle(audioAttributes), handleAudioFocus)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1658,9 +1678,10 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTrackSelectionParameters(
|
public void setTrackSelectionParameters(
|
||||||
@Nullable IMediaController caller, int sequenceNumber, Bundle trackSelectionParametersBundle)
|
@Nullable IMediaController caller,
|
||||||
throws RemoteException {
|
int sequenceNumber,
|
||||||
if (caller == null) {
|
@Nullable Bundle trackSelectionParametersBundle) {
|
||||||
|
if (caller == null || trackSelectionParametersBundle == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TrackSelectionParameters trackSelectionParameters;
|
TrackSelectionParameters trackSelectionParameters;
|
||||||
@ -1689,14 +1710,18 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getLibraryRoot(
|
public void getLibraryRoot(
|
||||||
@Nullable IMediaController caller, int sequenceNumber, @Nullable Bundle libraryParamsBundle)
|
@Nullable IMediaController caller, int sequenceNumber, @Nullable Bundle libraryParamsBundle) {
|
||||||
throws RuntimeException {
|
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@Nullable
|
@Nullable LibraryParams libraryParams;
|
||||||
LibraryParams libraryParams =
|
try {
|
||||||
|
libraryParams =
|
||||||
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for LibraryParams", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchSessionTaskWithSessionCommand(
|
dispatchSessionTaskWithSessionCommand(
|
||||||
caller,
|
caller,
|
||||||
sequenceNumber,
|
sequenceNumber,
|
||||||
@ -1708,8 +1733,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getItem(
|
public void getItem(
|
||||||
@Nullable IMediaController caller, int sequenceNumber, @Nullable String mediaId)
|
@Nullable IMediaController caller, int sequenceNumber, @Nullable String mediaId) {
|
||||||
throws RuntimeException {
|
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1730,11 +1754,10 @@ import java.util.concurrent.ExecutionException;
|
|||||||
public void getChildren(
|
public void getChildren(
|
||||||
@Nullable IMediaController caller,
|
@Nullable IMediaController caller,
|
||||||
int sequenceNumber,
|
int sequenceNumber,
|
||||||
String parentId,
|
@Nullable String parentId,
|
||||||
int page,
|
int page,
|
||||||
int pageSize,
|
int pageSize,
|
||||||
@Nullable Bundle libraryParamsBundle)
|
@Nullable Bundle libraryParamsBundle) {
|
||||||
throws RuntimeException {
|
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1750,9 +1773,14 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "getChildren(): Ignoring pageSize less than 1");
|
Log.w(TAG, "getChildren(): Ignoring pageSize less than 1");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@Nullable
|
@Nullable LibraryParams libraryParams;
|
||||||
LibraryParams libraryParams =
|
try {
|
||||||
|
libraryParams =
|
||||||
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for LibraryParams", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchSessionTaskWithSessionCommand(
|
dispatchSessionTaskWithSessionCommand(
|
||||||
caller,
|
caller,
|
||||||
sequenceNumber,
|
sequenceNumber,
|
||||||
@ -1767,7 +1795,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
public void search(
|
public void search(
|
||||||
@Nullable IMediaController caller,
|
@Nullable IMediaController caller,
|
||||||
int sequenceNumber,
|
int sequenceNumber,
|
||||||
String query,
|
@Nullable String query,
|
||||||
@Nullable Bundle libraryParamsBundle) {
|
@Nullable Bundle libraryParamsBundle) {
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
@ -1776,9 +1804,14 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "search(): Ignoring empty query");
|
Log.w(TAG, "search(): Ignoring empty query");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@Nullable
|
@Nullable LibraryParams libraryParams;
|
||||||
LibraryParams libraryParams =
|
try {
|
||||||
|
libraryParams =
|
||||||
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for LibraryParams", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchSessionTaskWithSessionCommand(
|
dispatchSessionTaskWithSessionCommand(
|
||||||
caller,
|
caller,
|
||||||
sequenceNumber,
|
sequenceNumber,
|
||||||
@ -1792,7 +1825,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
public void getSearchResult(
|
public void getSearchResult(
|
||||||
@Nullable IMediaController caller,
|
@Nullable IMediaController caller,
|
||||||
int sequenceNumber,
|
int sequenceNumber,
|
||||||
String query,
|
@Nullable String query,
|
||||||
int page,
|
int page,
|
||||||
int pageSize,
|
int pageSize,
|
||||||
@Nullable Bundle libraryParamsBundle) {
|
@Nullable Bundle libraryParamsBundle) {
|
||||||
@ -1811,9 +1844,14 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "getSearchResult(): Ignoring pageSize less than 1");
|
Log.w(TAG, "getSearchResult(): Ignoring pageSize less than 1");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@Nullable
|
@Nullable LibraryParams libraryParams;
|
||||||
LibraryParams libraryParams =
|
try {
|
||||||
|
libraryParams =
|
||||||
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for LibraryParams", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchSessionTaskWithSessionCommand(
|
dispatchSessionTaskWithSessionCommand(
|
||||||
caller,
|
caller,
|
||||||
sequenceNumber,
|
sequenceNumber,
|
||||||
@ -1828,7 +1866,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
public void subscribe(
|
public void subscribe(
|
||||||
@Nullable IMediaController caller,
|
@Nullable IMediaController caller,
|
||||||
int sequenceNumber,
|
int sequenceNumber,
|
||||||
String parentId,
|
@Nullable String parentId,
|
||||||
@Nullable Bundle libraryParamsBundle) {
|
@Nullable Bundle libraryParamsBundle) {
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
@ -1837,9 +1875,14 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "subscribe(): Ignoring empty parentId");
|
Log.w(TAG, "subscribe(): Ignoring empty parentId");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@Nullable
|
@Nullable LibraryParams libraryParams;
|
||||||
LibraryParams libraryParams =
|
try {
|
||||||
|
libraryParams =
|
||||||
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
libraryParamsBundle == null ? null : LibraryParams.fromBundle(libraryParamsBundle);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for LibraryParams", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchSessionTaskWithSessionCommand(
|
dispatchSessionTaskWithSessionCommand(
|
||||||
caller,
|
caller,
|
||||||
sequenceNumber,
|
sequenceNumber,
|
||||||
@ -1850,7 +1893,8 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unsubscribe(@Nullable IMediaController caller, int sequenceNumber, String parentId) {
|
public void unsubscribe(
|
||||||
|
@Nullable IMediaController caller, int sequenceNumber, @Nullable String parentId) {
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package androidx.media3.session;
|
||||||
|
|
||||||
|
import static androidx.media3.test.utils.TestUtil.getThrowingBundle;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.media3.common.Player;
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer;
|
||||||
|
import androidx.media3.test.utils.TestExoPlayerBuilder;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
/** Unit test for {@link MediaControllerStub}. */
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class MediaControllerStubTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invalidBinderArguments_doNotCrashController() throws Exception {
|
||||||
|
// Access controller stub directly and then send invalid arguments. None of them should crash
|
||||||
|
// the controller and this test asserts this by running through without throwing an exception.
|
||||||
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||||
|
MediaSession session = new MediaSession.Builder(context, player).build();
|
||||||
|
MediaController controller =
|
||||||
|
new MediaController.Builder(context, session.getToken()).buildAsync().get();
|
||||||
|
IMediaController binder = controller.getBinder();
|
||||||
|
|
||||||
|
// Call methods with non-primitive parameters set to null.
|
||||||
|
binder.onConnected(/* seq= */ 0, /* connectionResult= */ null);
|
||||||
|
binder.onSessionResult(/* seq= */ 0, /* sessionResult= */ null);
|
||||||
|
binder.onLibraryResult(/* seq= */ 0, /* libraryResult= */ null);
|
||||||
|
binder.onSetCustomLayout(/* seq= */ 0, /* commandButtonList= */ null);
|
||||||
|
binder.onCustomCommand(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* command= */ new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_SEARCH).toBundle(),
|
||||||
|
/* args= */ null);
|
||||||
|
binder.onCustomCommand(/* seq= */ 0, /* command= */ null, /* args= */ new Bundle());
|
||||||
|
binder.onPlayerInfoChanged(
|
||||||
|
/* seq= */ 0, /* playerInfoBundle= */ null, /* isTimelineExcluded= */ false);
|
||||||
|
binder.onPlayerInfoChangedWithExclusions(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* playerInfoBundle= */ null,
|
||||||
|
/* playerInfoExclusions= */ new PlayerInfo.BundlingExclusions(
|
||||||
|
/* isTimelineExcluded= */ true, /* areCurrentTracksExcluded= */ false)
|
||||||
|
.toBundle());
|
||||||
|
binder.onPlayerInfoChangedWithExclusions(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* playerInfoBundle= */ PlayerInfo.DEFAULT.toBundle(),
|
||||||
|
/* playerInfoExclusions= */ null);
|
||||||
|
binder.onPeriodicSessionPositionInfoChanged(/* seq= */ 0, /* sessionPositionInfo= */ null);
|
||||||
|
binder.onAvailableCommandsChangedFromPlayer(/* seq= */ 0, /* commandsBundle= */ null);
|
||||||
|
binder.onAvailableCommandsChangedFromSession(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* sessionCommandsBundle= */ new SessionCommands.Builder().build().toBundle(),
|
||||||
|
/* playerCommandsBundle= */ null);
|
||||||
|
binder.onAvailableCommandsChangedFromSession(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* sessionCommandsBundle= */ null,
|
||||||
|
/* playerCommandsBundle= */ new Player.Commands.Builder().build().toBundle());
|
||||||
|
binder.onExtrasChanged(/* seq= */ 0, /* extras= */ null);
|
||||||
|
binder.onSessionActivityChanged(/* seq= */ 0, /* pendingIntent= */ null);
|
||||||
|
binder.onChildrenChanged(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* parentId= */ null,
|
||||||
|
/* itemCount= */ 1,
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.onChildrenChanged(
|
||||||
|
/* seq= */ 0, /* parentId= */ "", /* itemCount= */ 1, /* libraryParams= */ null);
|
||||||
|
binder.onSearchResultChanged(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* query= */ null,
|
||||||
|
/* itemCount= */ 1,
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.onSearchResultChanged(
|
||||||
|
/* seq= */ 0, /* query= */ "", /* itemCount= */ 1, /* libraryParams= */ null);
|
||||||
|
|
||||||
|
// Call methods with non-null arguments, but invalid Bundles.
|
||||||
|
binder.onConnected(/* seq= */ 0, /* connectionResult= */ getThrowingBundle());
|
||||||
|
binder.onSessionResult(/* seq= */ 0, /* sessionResult= */ getThrowingBundle());
|
||||||
|
binder.onLibraryResult(/* seq= */ 0, /* libraryResult= */ getThrowingBundle());
|
||||||
|
binder.onSetCustomLayout(
|
||||||
|
/* seq= */ 0, /* commandButtonList= */ ImmutableList.of(getThrowingBundle()));
|
||||||
|
binder.onCustomCommand(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* command= */ new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_SEARCH).toBundle(),
|
||||||
|
/* args= */ getThrowingBundle());
|
||||||
|
binder.onCustomCommand(
|
||||||
|
/* seq= */ 0, /* command= */ getThrowingBundle(), /* args= */ new Bundle());
|
||||||
|
binder.onPlayerInfoChanged(
|
||||||
|
/* seq= */ 0, /* playerInfoBundle= */ getThrowingBundle(), /* isTimelineExcluded= */ false);
|
||||||
|
binder.onPlayerInfoChangedWithExclusions(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* playerInfoBundle= */ getThrowingBundle(),
|
||||||
|
/* playerInfoExclusions= */ new PlayerInfo.BundlingExclusions(
|
||||||
|
/* isTimelineExcluded= */ true, /* areCurrentTracksExcluded= */ false)
|
||||||
|
.toBundle());
|
||||||
|
binder.onPlayerInfoChangedWithExclusions(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* playerInfoBundle= */ PlayerInfo.DEFAULT.toBundle(),
|
||||||
|
/* playerInfoExclusions= */ getThrowingBundle());
|
||||||
|
binder.onPeriodicSessionPositionInfoChanged(
|
||||||
|
/* seq= */ 0, /* sessionPositionInfo= */ getThrowingBundle());
|
||||||
|
binder.onAvailableCommandsChangedFromPlayer(
|
||||||
|
/* seq= */ 0, /* commandsBundle= */ getThrowingBundle());
|
||||||
|
binder.onAvailableCommandsChangedFromSession(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* sessionCommandsBundle= */ new SessionCommands.Builder().build().toBundle(),
|
||||||
|
/* playerCommandsBundle= */ getThrowingBundle());
|
||||||
|
binder.onAvailableCommandsChangedFromSession(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* sessionCommandsBundle= */ getThrowingBundle(),
|
||||||
|
/* playerCommandsBundle= */ new Player.Commands.Builder().build().toBundle());
|
||||||
|
binder.onExtrasChanged(/* seq= */ 0, /* extras= */ getThrowingBundle());
|
||||||
|
binder.onChildrenChanged(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* parentId= */ "",
|
||||||
|
/* itemCount= */ 1,
|
||||||
|
/* libraryParams= */ getThrowingBundle());
|
||||||
|
binder.onSearchResultChanged(
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* query= */ "",
|
||||||
|
/* itemCount= */ 1,
|
||||||
|
/* libraryParams= */ getThrowingBundle());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,436 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package androidx.media3.session;
|
||||||
|
|
||||||
|
import static androidx.media3.test.utils.TestUtil.getThrowingBundle;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import androidx.media3.common.AudioAttributes;
|
||||||
|
import androidx.media3.common.BundleListRetriever;
|
||||||
|
import androidx.media3.common.HeartRating;
|
||||||
|
import androidx.media3.common.MediaItem;
|
||||||
|
import androidx.media3.common.MediaMetadata;
|
||||||
|
import androidx.media3.common.PlaybackParameters;
|
||||||
|
import androidx.media3.common.Player;
|
||||||
|
import androidx.media3.common.TrackSelectionParameters;
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer;
|
||||||
|
import androidx.media3.test.utils.TestExoPlayerBuilder;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
/** Unit test for {@link MediaSessionStub}. */
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class MediaSessionStubTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invalidBinderArguments_doNotCrashSession() throws Exception {
|
||||||
|
// Access session stub directly and then send invalid arguments. None of them should crash the
|
||||||
|
// session app and this test asserts this by running through without throwing an exception.
|
||||||
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||||
|
MediaSession session = new MediaSession.Builder(context, player).setId("invalidArgs").build();
|
||||||
|
IMediaSession binder = (IMediaSession) session.getToken().getBinder();
|
||||||
|
|
||||||
|
// Call methods with caller==null and valid additional parameters.
|
||||||
|
binder.setVolume(/* caller= */ null, /* seq= */ 0, /* volume= */ 0);
|
||||||
|
binder.setDeviceVolume(/* caller= */ null, /* seq= */ 0, /* volume= */ 0);
|
||||||
|
binder.setDeviceVolumeWithFlags(
|
||||||
|
/* caller= */ null, /* seq= */ 0, /* volume= */ 0, /* flags= */ 0);
|
||||||
|
binder.increaseDeviceVolume(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.increaseDeviceVolumeWithFlags(/* caller= */ null, /* seq= */ 0, /* flags= */ 0);
|
||||||
|
binder.decreaseDeviceVolume(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.decreaseDeviceVolumeWithFlags(/* caller= */ null, /* seq= */ 0, /* flags= */ 0);
|
||||||
|
binder.setDeviceMuted(/* caller= */ null, /* seq= */ 0, /* muted= */ false);
|
||||||
|
binder.setDeviceMutedWithFlags(
|
||||||
|
/* caller= */ null, /* seq= */ 0, /* muted= */ false, /* flags= */ 0);
|
||||||
|
binder.setAudioAttributes(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* audioAttributes= */ AudioAttributes.DEFAULT.toBundle(),
|
||||||
|
/* handleAudioFocus= */ false);
|
||||||
|
binder.setMediaItem(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItemBundle= */ new MediaItem.Builder().build().toBundle());
|
||||||
|
binder.setMediaItemWithStartPosition(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItemBundle= */ new MediaItem.Builder().build().toBundle(),
|
||||||
|
/* startPositionMs= */ 0);
|
||||||
|
binder.setMediaItemWithResetPosition(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItemBundle= */ new MediaItem.Builder().build().toBundle(),
|
||||||
|
/* resetPosition= */ false);
|
||||||
|
binder.setMediaItems(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(
|
||||||
|
ImmutableList.of(new MediaItem.Builder().build().toBundle())));
|
||||||
|
binder.setMediaItemsWithResetPosition(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(
|
||||||
|
ImmutableList.of(new MediaItem.Builder().build().toBundle())),
|
||||||
|
/* resetPosition= */ false);
|
||||||
|
binder.setMediaItemsWithStartIndex(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(
|
||||||
|
ImmutableList.of(new MediaItem.Builder().build().toBundle())),
|
||||||
|
/* startIndex= */ 0,
|
||||||
|
/* startPositionMs= */ 0);
|
||||||
|
binder.setPlayWhenReady(/* caller= */ null, /* seq= */ 0, /* playWhenReady= */ false);
|
||||||
|
binder.onControllerResult(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* controllerResult= */ new SessionResult(SessionResult.RESULT_SUCCESS).toBundle());
|
||||||
|
binder.connect(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* connectionRequest= */ new ConnectionRequest(
|
||||||
|
"pkg", /* pid= */ 0, /* connectionHints= */ new Bundle())
|
||||||
|
.toBundle());
|
||||||
|
binder.onCustomCommand(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* sessionCommand= */ new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_ITEM)
|
||||||
|
.toBundle(),
|
||||||
|
/* args= */ new Bundle());
|
||||||
|
binder.setRepeatMode(
|
||||||
|
/* caller= */ null, /* seq= */ 0, /* repeatMode= */ Player.REPEAT_MODE_OFF);
|
||||||
|
binder.setShuffleModeEnabled(/* caller= */ null, /* seq= */ 0, /* shuffleModeEnabled= */ false);
|
||||||
|
binder.removeMediaItem(/* caller= */ null, /* seq= */ 0, /* index= */ 0);
|
||||||
|
binder.removeMediaItems(/* caller= */ null, /* seq= */ 0, /* fromIndex= */ 0, /* toIndex= */ 0);
|
||||||
|
binder.clearMediaItems(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.moveMediaItem(
|
||||||
|
/* caller= */ null, /* seq= */ 0, /* currentIndex= */ 0, /* newIndex= */ 0);
|
||||||
|
binder.moveMediaItems(
|
||||||
|
/* caller= */ null, /* seq= */ 0, /* fromIndex= */ 0, /* toIndex= */ 0, /* newIndex= */ 0);
|
||||||
|
binder.replaceMediaItem(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* index= */ 0,
|
||||||
|
/* mediaItemBundle= */ new MediaItem.Builder().build().toBundle());
|
||||||
|
binder.replaceMediaItems(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* fromIndex= */ 0,
|
||||||
|
/* toIndex= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(
|
||||||
|
ImmutableList.of(new MediaItem.Builder().build().toBundle())));
|
||||||
|
binder.play(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.pause(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.prepare(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.setPlaybackParameters(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* playbackParametersBundle= */ new PlaybackParameters(/* speed= */ 1f).toBundle());
|
||||||
|
binder.setPlaybackSpeed(/* caller= */ null, /* seq= */ 0, /* speed= */ 0);
|
||||||
|
binder.addMediaItem(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItemBundle= */ new MediaItem.Builder().build().toBundle());
|
||||||
|
binder.addMediaItemWithIndex(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* index= */ 0,
|
||||||
|
/* mediaItemBundle= */ new MediaItem.Builder().build().toBundle());
|
||||||
|
binder.addMediaItems(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(
|
||||||
|
ImmutableList.of(new MediaItem.Builder().build().toBundle())));
|
||||||
|
binder.addMediaItemsWithIndex(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* index= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(
|
||||||
|
ImmutableList.of(new MediaItem.Builder().build().toBundle())));
|
||||||
|
binder.setPlaylistMetadata(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* playlistMetadata= */ new MediaMetadata.Builder().build().toBundle());
|
||||||
|
binder.stop(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.release(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.seekToDefaultPosition(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.seekToDefaultPositionWithMediaItemIndex(
|
||||||
|
/* caller= */ null, /* seq= */ 0, /* mediaItemIndex= */ 0);
|
||||||
|
binder.seekTo(/* caller= */ null, /* seq= */ 0, /* positionMs= */ 0);
|
||||||
|
binder.seekToWithMediaItemIndex(
|
||||||
|
/* caller= */ null, /* seq= */ 0, /* mediaItemIndex= */ 0, /* positionMs= */ 0);
|
||||||
|
binder.seekBack(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.seekForward(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.seekToPreviousMediaItem(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.seekToNextMediaItem(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.setVideoSurface(/* caller= */ null, /* seq= */ 0, /* surface= */ null);
|
||||||
|
binder.flushCommandQueue(/* caller= */ null);
|
||||||
|
binder.seekToPrevious(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.seekToNext(/* caller= */ null, /* seq= */ 0);
|
||||||
|
binder.setTrackSelectionParameters(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* trackSelectionParametersBundle= */ new TrackSelectionParameters.Builder(context)
|
||||||
|
.build()
|
||||||
|
.toBundle());
|
||||||
|
binder.setRatingWithMediaId(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaId= */ "",
|
||||||
|
/* rating= */ new HeartRating().toBundle());
|
||||||
|
binder.setRating(/* caller= */ null, /* seq= */ 0, /* rating= */ new HeartRating().toBundle());
|
||||||
|
binder.getLibraryRoot(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.getItem(/* caller= */ null, /* seq= */ 0, /* mediaId= */ "");
|
||||||
|
binder.getChildren(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* parentId= */ "",
|
||||||
|
/* page= */ 0,
|
||||||
|
/* pageSize= */ 0,
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.search(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* query= */ "",
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.getSearchResult(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* query= */ "",
|
||||||
|
/* page= */ 0,
|
||||||
|
/* pageSize= */ 0,
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.subscribe(
|
||||||
|
/* caller= */ null,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* parentId= */ "",
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.unsubscribe(/* caller= */ null, /* seq= */ 0, /* parentId= */ "");
|
||||||
|
|
||||||
|
// Call methods with non-null caller, but other non-primitive parameters set to null.
|
||||||
|
MediaController controller =
|
||||||
|
new MediaController.Builder(context, session.getToken()).buildAsync().get();
|
||||||
|
IMediaController caller = controller.getBinder();
|
||||||
|
binder.setAudioAttributes(
|
||||||
|
caller, /* seq= */ 0, /* audioAttributes= */ null, /* handleAudioFocus= */ false);
|
||||||
|
binder.setMediaItem(caller, /* seq= */ 0, /* mediaItemBundle= */ null);
|
||||||
|
binder.setMediaItemWithStartPosition(
|
||||||
|
caller, /* seq= */ 0, /* mediaItemBundle= */ null, /* startPositionMs= */ 0);
|
||||||
|
binder.setMediaItemWithResetPosition(
|
||||||
|
caller, /* seq= */ 0, /* mediaItemBundle= */ null, /* resetPosition= */ false);
|
||||||
|
binder.setMediaItems(caller, /* seq= */ 0, /* mediaItems= */ null);
|
||||||
|
binder.setMediaItemsWithResetPosition(
|
||||||
|
caller, /* seq= */ 0, /* mediaItems= */ null, /* resetPosition= */ false);
|
||||||
|
binder.setMediaItemsWithStartIndex(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ null,
|
||||||
|
/* startIndex= */ 0,
|
||||||
|
/* startPositionMs= */ 0);
|
||||||
|
binder.onControllerResult(caller, /* seq= */ 0, /* controllerResult= */ null);
|
||||||
|
binder.connect(caller, /* seq= */ 0, /* connectionRequest= */ null);
|
||||||
|
binder.onCustomCommand(
|
||||||
|
caller, /* seq= */ 0, /* sessionCommand= */ null, /* args= */ new Bundle());
|
||||||
|
binder.onCustomCommand(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* sessionCommand= */ new SessionCommand(SessionCommand.COMMAND_CODE_LIBRARY_GET_ITEM)
|
||||||
|
.toBundle(),
|
||||||
|
/* args= */ null);
|
||||||
|
binder.replaceMediaItem(caller, /* seq= */ 0, /* index= */ 0, /* mediaItemBundle= */ null);
|
||||||
|
binder.replaceMediaItems(
|
||||||
|
caller, /* seq= */ 0, /* fromIndex= */ 0, /* toIndex= */ 0, /* mediaItems= */ null);
|
||||||
|
binder.setPlaybackParameters(caller, /* seq= */ 0, /* playbackParametersBundle= */ null);
|
||||||
|
binder.addMediaItem(caller, /* seq= */ 0, /* mediaItemBundle= */ null);
|
||||||
|
binder.addMediaItemWithIndex(caller, /* seq= */ 0, /* index= */ 0, /* mediaItemBundle= */ null);
|
||||||
|
binder.addMediaItems(caller, /* seq= */ 0, /* mediaItems= */ null);
|
||||||
|
binder.addMediaItemsWithIndex(caller, /* seq= */ 0, /* index= */ 0, /* mediaItems= */ null);
|
||||||
|
binder.setPlaylistMetadata(caller, /* seq= */ 0, /* playlistMetadata= */ null);
|
||||||
|
binder.setTrackSelectionParameters(
|
||||||
|
caller, /* seq= */ 0, /* trackSelectionParametersBundle= */ null);
|
||||||
|
binder.setRatingWithMediaId(
|
||||||
|
caller, /* seq= */ 0, /* mediaId= */ null, /* rating= */ new HeartRating().toBundle());
|
||||||
|
binder.setRatingWithMediaId(caller, /* seq= */ 0, /* mediaId= */ "", /* rating= */ null);
|
||||||
|
binder.setRating(caller, /* seq= */ 0, /* rating= */ null);
|
||||||
|
binder.getLibraryRoot(caller, /* seq= */ 0, /* libraryParams= */ null);
|
||||||
|
binder.getItem(caller, /* seq= */ 0, /* mediaId= */ null);
|
||||||
|
binder.getChildren(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* parentId= */ null,
|
||||||
|
/* page= */ 0,
|
||||||
|
/* pageSize= */ 0,
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.getChildren(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* parentId= */ "",
|
||||||
|
/* page= */ 0,
|
||||||
|
/* pageSize= */ 0,
|
||||||
|
/* libraryParams= */ null);
|
||||||
|
binder.search(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* query= */ null,
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.search(caller, /* seq= */ 0, /* query= */ "", /* libraryParams= */ null);
|
||||||
|
binder.getSearchResult(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* query= */ null,
|
||||||
|
/* page= */ 0,
|
||||||
|
/* pageSize= */ 0,
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.getSearchResult(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* query= */ "",
|
||||||
|
/* page= */ 0,
|
||||||
|
/* pageSize= */ 0,
|
||||||
|
/* libraryParams= */ null);
|
||||||
|
binder.subscribe(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* parentId= */ null,
|
||||||
|
/* libraryParams= */ new MediaLibraryService.LibraryParams.Builder().build().toBundle());
|
||||||
|
binder.subscribe(caller, /* seq= */ 0, /* parentId= */ "", /* libraryParams= */ null);
|
||||||
|
binder.unsubscribe(caller, /* seq= */ 0, /* parentId= */ null);
|
||||||
|
|
||||||
|
// Call methods with non-null arguments, but invalid Bundles.
|
||||||
|
IBinder noopBinder = new Binder() {};
|
||||||
|
binder.setAudioAttributes(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* audioAttributes= */ getThrowingBundle(),
|
||||||
|
/* handleAudioFocus= */ false);
|
||||||
|
binder.setMediaItem(caller, /* seq= */ 0, /* mediaItemBundle= */ getThrowingBundle());
|
||||||
|
binder.setMediaItemWithStartPosition(
|
||||||
|
caller, /* seq= */ 0, /* mediaItemBundle= */ getThrowingBundle(), /* startPositionMs= */ 0);
|
||||||
|
binder.setMediaItemWithResetPosition(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItemBundle= */ getThrowingBundle(),
|
||||||
|
/* resetPosition= */ false);
|
||||||
|
binder.setMediaItems(caller, /* seq= */ 0, /* mediaItems= */ noopBinder);
|
||||||
|
binder.setMediaItems(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(ImmutableList.of(getThrowingBundle())));
|
||||||
|
binder.setMediaItemsWithResetPosition(
|
||||||
|
caller, /* seq= */ 0, /* mediaItems= */ noopBinder, /* resetPosition= */ false);
|
||||||
|
binder.setMediaItemsWithResetPosition(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(ImmutableList.of(getThrowingBundle())),
|
||||||
|
/* resetPosition= */ false);
|
||||||
|
binder.setMediaItemsWithStartIndex(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ noopBinder,
|
||||||
|
/* startIndex= */ 0,
|
||||||
|
/* startPositionMs= */ 0);
|
||||||
|
binder.setMediaItemsWithStartIndex(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(ImmutableList.of(getThrowingBundle())),
|
||||||
|
/* startIndex= */ 0,
|
||||||
|
/* startPositionMs= */ 0);
|
||||||
|
binder.onControllerResult(caller, /* seq= */ 0, /* controllerResult= */ getThrowingBundle());
|
||||||
|
binder.onCustomCommand(
|
||||||
|
caller, /* seq= */ 0, /* sessionCommand= */ getThrowingBundle(), /* args= */ new Bundle());
|
||||||
|
binder.replaceMediaItem(
|
||||||
|
caller, /* seq= */ 0, /* index= */ 0, /* mediaItemBundle= */ getThrowingBundle());
|
||||||
|
binder.replaceMediaItems(
|
||||||
|
caller, /* seq= */ 0, /* fromIndex= */ 0, /* toIndex= */ 0, /* mediaItems= */ noopBinder);
|
||||||
|
binder.replaceMediaItems(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* fromIndex= */ 0,
|
||||||
|
/* toIndex= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(ImmutableList.of(getThrowingBundle())));
|
||||||
|
binder.setPlaybackParameters(
|
||||||
|
caller, /* seq= */ 0, /* playbackParametersBundle= */ getThrowingBundle());
|
||||||
|
binder.addMediaItem(caller, /* seq= */ 0, /* mediaItemBundle= */ getThrowingBundle());
|
||||||
|
binder.addMediaItemWithIndex(
|
||||||
|
caller, /* seq= */ 0, /* index= */ 0, /* mediaItemBundle= */ getThrowingBundle());
|
||||||
|
binder.addMediaItems(caller, /* seq= */ 0, /* mediaItems= */ noopBinder);
|
||||||
|
binder.addMediaItems(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(ImmutableList.of(getThrowingBundle())));
|
||||||
|
binder.addMediaItemsWithIndex(
|
||||||
|
caller, /* seq= */ 0, /* index= */ 0, /* mediaItems= */ noopBinder);
|
||||||
|
binder.addMediaItemsWithIndex(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* index= */ 0,
|
||||||
|
/* mediaItems= */ new BundleListRetriever(ImmutableList.of(getThrowingBundle())));
|
||||||
|
binder.setPlaylistMetadata(caller, /* seq= */ 0, /* playlistMetadata= */ getThrowingBundle());
|
||||||
|
binder.setTrackSelectionParameters(
|
||||||
|
caller, /* seq= */ 0, /* trackSelectionParametersBundle= */ getThrowingBundle());
|
||||||
|
binder.setRatingWithMediaId(
|
||||||
|
caller, /* seq= */ 0, /* mediaId= */ "", /* rating= */ getThrowingBundle());
|
||||||
|
binder.setRating(caller, /* seq= */ 0, /* rating= */ getThrowingBundle());
|
||||||
|
binder.getLibraryRoot(caller, /* seq= */ 0, /* libraryParams= */ getThrowingBundle());
|
||||||
|
binder.getChildren(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* parentId= */ "",
|
||||||
|
/* page= */ 0,
|
||||||
|
/* pageSize= */ 0,
|
||||||
|
/* libraryParams= */ getThrowingBundle());
|
||||||
|
binder.search(caller, /* seq= */ 0, /* query= */ "", /* libraryParams= */ getThrowingBundle());
|
||||||
|
binder.getSearchResult(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* query= */ "",
|
||||||
|
/* page= */ 0,
|
||||||
|
/* pageSize= */ 0,
|
||||||
|
/* libraryParams= */ getThrowingBundle());
|
||||||
|
binder.subscribe(
|
||||||
|
caller, /* seq= */ 0, /* parentId= */ "", /* libraryParams= */ getThrowingBundle());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void binderConnectRequest_withInvalidController_doesNotCrashSession() throws Exception {
|
||||||
|
// Obtain a direct reference to binder and attempt to connect with an invalid controller. This
|
||||||
|
// should not crash the session app and this test asserts this by running through without
|
||||||
|
// throwing an exception.
|
||||||
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
ExoPlayer player = new TestExoPlayerBuilder(context).build();
|
||||||
|
MediaSession session = new MediaSession.Builder(context, player).setId("connect").build();
|
||||||
|
IMediaSession binder = (IMediaSession) session.getToken().getBinder();
|
||||||
|
MediaController controller =
|
||||||
|
new MediaController.Builder(context, session.getToken()).buildAsync().get();
|
||||||
|
IMediaController caller = controller.getBinder();
|
||||||
|
|
||||||
|
binder.connect(
|
||||||
|
caller,
|
||||||
|
/* seq= */ 0,
|
||||||
|
/* connectionRequest= */ new ConnectionRequest(
|
||||||
|
/* packageName= */ "invalud", /* pid= */ 9999, /* connectionHints= */ new Bundle())
|
||||||
|
.toBundle());
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.test.utils;
|
package androidx.media3.test.utils;
|
||||||
|
|
||||||
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -25,6 +26,8 @@ import android.graphics.BitmapFactory;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcel;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
@ -593,6 +596,26 @@ public class TestUtil {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns a {@link Bundle} that will throw an exception at the first attempt to read a value. */
|
||||||
|
public static Bundle getThrowingBundle() {
|
||||||
|
// Create Bundle containing a Parcelable class that will require a ClassLoader.
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putParcelable("0", new StreamKey(0, 0));
|
||||||
|
// Serialize this Bundle to a Parcel to remove the direct object reference.
|
||||||
|
Parcel parcel = Parcel.obtain();
|
||||||
|
parcel.writeBundle(bundle);
|
||||||
|
// Read the same Bundle from the Parcel again, but with a ClassLoader that can't load the class.
|
||||||
|
parcel.setDataPosition(0);
|
||||||
|
ClassLoader throwingClassLoader =
|
||||||
|
new ClassLoader() {
|
||||||
|
@Override
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
throw new ClassNotFoundException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return checkNotNull(parcel.readBundle(throwingClassLoader));
|
||||||
|
}
|
||||||
|
|
||||||
private static final class NoUidOrShufflingTimeline extends Timeline {
|
private static final class NoUidOrShufflingTimeline extends Timeline {
|
||||||
|
|
||||||
private final Timeline delegate;
|
private final Timeline delegate;
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package androidx.media3.test.utils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
/** Unit tests for {@link TestUtil}. */
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class TestUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getThrowingBundle_throwsWhenUsed() {
|
||||||
|
Bundle bundle = TestUtil.getThrowingBundle();
|
||||||
|
|
||||||
|
assertThrows(RuntimeException.class, () -> bundle.getInt("0"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user