Exclude tracks from PlayerInfo
if not changed
This change includes a change in the `IMediaController.aidl` file and needs to provide backwards compatibility for when a client connects that is of an older or newer version of the current service implementation. This CL proposes to create a new AIDL method `onPlayerInfoChangedWithExtensions` that is easier to extend in the future because it does use an `Bundle` rather than primitives. A `Bundle` can be changed in a backward/forwards compatible way in case we need further changes. The compatibility handling is provided in `MediaSessionStub` and `MediaControllerStub`. The approach is not based on specific AIDL/Binder features but implemented fully in application code. Issue: androidx/media#102 #minor-release PiperOrigin-RevId: 490483068
This commit is contained in:
parent
10fac6847a
commit
3d8c52f28d
@ -677,7 +677,8 @@ public interface Player {
|
|||||||
* to the current {@link #getRepeatMode() repeat mode}.
|
* to the current {@link #getRepeatMode() repeat mode}.
|
||||||
*
|
*
|
||||||
* <p>Note that this callback is also called when the playlist becomes non-empty or empty as a
|
* <p>Note that this callback is also called when the playlist becomes non-empty or empty as a
|
||||||
* consequence of a playlist change.
|
* consequence of a playlist change or {@linkplain #onAvailableCommandsChanged(Commands) a
|
||||||
|
* change in available commands}.
|
||||||
*
|
*
|
||||||
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
|
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
|
||||||
* other events that happen in the same {@link Looper} message queue iteration.
|
* other events that happen in the same {@link Looper} message queue iteration.
|
||||||
|
@ -35,14 +35,19 @@ oneway interface IMediaController {
|
|||||||
void onSetCustomLayout(int seq, in List<Bundle> commandButtonList) = 3003;
|
void onSetCustomLayout(int seq, in List<Bundle> commandButtonList) = 3003;
|
||||||
void onCustomCommand(int seq, in Bundle command, in Bundle args) = 3004;
|
void onCustomCommand(int seq, in Bundle command, in Bundle args) = 3004;
|
||||||
void onDisconnected(int seq) = 3005;
|
void onDisconnected(int seq) = 3005;
|
||||||
void onPlayerInfoChanged(int seq, in Bundle playerInfoBundle, boolean isTimelineExcluded) = 3006;
|
/** Deprecated: Use onPlayerInfoChangedWithExclusions from MediaControllerStub#VERSION_INT=2. */
|
||||||
|
void onPlayerInfoChanged(
|
||||||
|
int seq, in Bundle playerInfoBundle, boolean isTimelineExcluded) = 3006;
|
||||||
|
/** Introduced to deprecate onPlayerInfoChanged (from MediaControllerStub#VERSION_INT=2). */
|
||||||
|
void onPlayerInfoChangedWithExclusions(
|
||||||
|
int seq, in Bundle playerInfoBundle, in Bundle playerInfoExclusions) = 3012;
|
||||||
void onPeriodicSessionPositionInfoChanged(int seq, in Bundle sessionPositionInfo) = 3007;
|
void onPeriodicSessionPositionInfoChanged(int seq, in Bundle sessionPositionInfo) = 3007;
|
||||||
void onAvailableCommandsChangedFromPlayer(int seq, in Bundle commandsBundle) = 3008;
|
void onAvailableCommandsChangedFromPlayer(int seq, in Bundle commandsBundle) = 3008;
|
||||||
void onAvailableCommandsChangedFromSession(
|
void onAvailableCommandsChangedFromSession(
|
||||||
int seq, in Bundle sessionCommandsBundle, in Bundle playerCommandsBundle) = 3009;
|
int seq, in Bundle sessionCommandsBundle, in Bundle playerCommandsBundle) = 3009;
|
||||||
void onRenderedFirstFrame(int seq) = 3010;
|
void onRenderedFirstFrame(int seq) = 3010;
|
||||||
void onExtrasChanged(int seq, in Bundle extras) = 3011;
|
void onExtrasChanged(int seq, in Bundle extras) = 3011;
|
||||||
// Next Id for MediaController: 3012
|
// Next Id for MediaController: 3013
|
||||||
|
|
||||||
void onChildrenChanged(
|
void onChildrenChanged(
|
||||||
int seq, String parentId, int itemCount, in @nullable Bundle libraryParams) = 4000;
|
int seq, String parentId, int itemCount, in @nullable Bundle libraryParams) = 4000;
|
||||||
|
@ -23,6 +23,7 @@ import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
|||||||
import static androidx.media3.common.util.Util.usToMs;
|
import static androidx.media3.common.util.Util.usToMs;
|
||||||
import static androidx.media3.session.MediaUtils.calculateBufferedPercentage;
|
import static androidx.media3.session.MediaUtils.calculateBufferedPercentage;
|
||||||
import static androidx.media3.session.MediaUtils.intersect;
|
import static androidx.media3.session.MediaUtils.intersect;
|
||||||
|
import static androidx.media3.session.MediaUtils.mergePlayerInfo;
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ import android.os.Process;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.support.v4.media.MediaBrowserCompat;
|
import android.support.v4.media.MediaBrowserCompat;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
@ -79,6 +81,7 @@ import androidx.media3.common.util.Log;
|
|||||||
import androidx.media3.common.util.Size;
|
import androidx.media3.common.util.Size;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.session.MediaController.MediaControllerImpl;
|
import androidx.media3.session.MediaController.MediaControllerImpl;
|
||||||
|
import androidx.media3.session.PlayerInfo.BundlingExclusions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
@ -129,7 +132,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
@Nullable private IMediaSession iSession;
|
@Nullable private IMediaSession iSession;
|
||||||
private long lastReturnedCurrentPositionMs;
|
private long lastReturnedCurrentPositionMs;
|
||||||
private long lastSetPlayWhenReadyCalledTimeMs;
|
private long lastSetPlayWhenReadyCalledTimeMs;
|
||||||
@Nullable private Timeline pendingPlayerInfoUpdateTimeline;
|
@Nullable private PlayerInfo pendingPlayerInfo;
|
||||||
|
@Nullable private BundlingExclusions pendingBundlingExclusions;
|
||||||
|
|
||||||
public MediaControllerImplBase(
|
public MediaControllerImplBase(
|
||||||
Context context,
|
Context context,
|
||||||
@ -2329,30 +2333,41 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // Implementing and calling deprecated listener method.
|
@SuppressWarnings("deprecation") // Implementing and calling deprecated listener method.
|
||||||
void onPlayerInfoChanged(PlayerInfo newPlayerInfo, boolean isTimelineExcluded) {
|
void onPlayerInfoChanged(PlayerInfo newPlayerInfo, BundlingExclusions bundlingExclusions) {
|
||||||
if (!isConnected()) {
|
if (!isConnected()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (pendingPlayerInfo != null && pendingBundlingExclusions != null) {
|
||||||
|
Pair<PlayerInfo, BundlingExclusions> mergedPlayerInfoUpdate =
|
||||||
|
mergePlayerInfo(
|
||||||
|
pendingPlayerInfo,
|
||||||
|
pendingBundlingExclusions,
|
||||||
|
newPlayerInfo,
|
||||||
|
bundlingExclusions,
|
||||||
|
intersectedPlayerCommands);
|
||||||
|
newPlayerInfo = mergedPlayerInfoUpdate.first;
|
||||||
|
bundlingExclusions = mergedPlayerInfoUpdate.second;
|
||||||
|
}
|
||||||
|
pendingPlayerInfo = null;
|
||||||
|
pendingBundlingExclusions = null;
|
||||||
if (!pendingMaskingSequencedFutureNumbers.isEmpty()) {
|
if (!pendingMaskingSequencedFutureNumbers.isEmpty()) {
|
||||||
// We are still waiting for all pending masking operations to be handled.
|
// We are still waiting for all pending masking operations to be handled.
|
||||||
if (!isTimelineExcluded) {
|
pendingPlayerInfo = newPlayerInfo;
|
||||||
pendingPlayerInfoUpdateTimeline = newPlayerInfo.timeline;
|
pendingBundlingExclusions = bundlingExclusions;
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PlayerInfo oldPlayerInfo = playerInfo;
|
PlayerInfo oldPlayerInfo = playerInfo;
|
||||||
if (isTimelineExcluded) {
|
|
||||||
newPlayerInfo =
|
|
||||||
newPlayerInfo.copyWithTimeline(
|
|
||||||
pendingPlayerInfoUpdateTimeline != null
|
|
||||||
? pendingPlayerInfoUpdateTimeline
|
|
||||||
: oldPlayerInfo.timeline);
|
|
||||||
}
|
|
||||||
// Assigning class variable now so that all getters called from listeners see the updated value.
|
// Assigning class variable now so that all getters called from listeners see the updated value.
|
||||||
// But we need to use a local final variable to ensure listeners get consistent parameters.
|
// But we need to use a local final variable to ensure listeners get consistent parameters.
|
||||||
playerInfo = newPlayerInfo;
|
playerInfo =
|
||||||
PlayerInfo finalPlayerInfo = newPlayerInfo;
|
mergePlayerInfo(
|
||||||
pendingPlayerInfoUpdateTimeline = null;
|
oldPlayerInfo,
|
||||||
|
/* oldBundlingExclusions= */ BundlingExclusions.NONE,
|
||||||
|
newPlayerInfo,
|
||||||
|
/* newBundlingExclusions= */ bundlingExclusions,
|
||||||
|
intersectedPlayerCommands)
|
||||||
|
.first;
|
||||||
|
PlayerInfo finalPlayerInfo = playerInfo;
|
||||||
PlaybackException oldPlayerError = oldPlayerInfo.playerError;
|
PlaybackException oldPlayerError = oldPlayerInfo.playerError;
|
||||||
PlaybackException playerError = finalPlayerInfo.playerError;
|
PlaybackException playerError = finalPlayerInfo.playerError;
|
||||||
boolean errorsMatch =
|
boolean errorsMatch =
|
||||||
@ -2397,7 +2412,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
/* eventFlag= */ Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED,
|
/* eventFlag= */ Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED,
|
||||||
listener -> listener.onShuffleModeEnabledChanged(finalPlayerInfo.shuffleModeEnabled));
|
listener -> listener.onShuffleModeEnabledChanged(finalPlayerInfo.shuffleModeEnabled));
|
||||||
}
|
}
|
||||||
if (!isTimelineExcluded && !Util.areEqual(oldPlayerInfo.timeline, finalPlayerInfo.timeline)) {
|
if (!Util.areEqual(oldPlayerInfo.timeline, finalPlayerInfo.timeline)) {
|
||||||
listeners.queueEvent(
|
listeners.queueEvent(
|
||||||
/* eventFlag= */ Player.EVENT_TIMELINE_CHANGED,
|
/* eventFlag= */ Player.EVENT_TIMELINE_CHANGED,
|
||||||
listener ->
|
listener ->
|
||||||
|
@ -26,6 +26,7 @@ import androidx.media3.common.Player.Commands;
|
|||||||
import androidx.media3.common.util.BundleableUtil;
|
import androidx.media3.common.util.BundleableUtil;
|
||||||
import androidx.media3.common.util.Log;
|
import androidx.media3.common.util.Log;
|
||||||
import androidx.media3.session.MediaLibraryService.LibraryParams;
|
import androidx.media3.session.MediaLibraryService.LibraryParams;
|
||||||
|
import androidx.media3.session.PlayerInfo.BundlingExclusions;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
@ -35,7 +36,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
private static final String TAG = "MediaControllerStub";
|
private static final String TAG = "MediaControllerStub";
|
||||||
|
|
||||||
/** The version of the IMediaController interface. */
|
/** The version of the IMediaController interface. */
|
||||||
public static final int VERSION_INT = 1;
|
public static final int VERSION_INT = 2;
|
||||||
|
|
||||||
private final WeakReference<MediaControllerImplBase> controller;
|
private final WeakReference<MediaControllerImplBase> controller;
|
||||||
|
|
||||||
@ -169,8 +170,23 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
controller -> controller.notifyPeriodicSessionPositionInfoChanged(sessionPositionInfo));
|
controller -> controller.notifyPeriodicSessionPositionInfoChanged(sessionPositionInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #onPlayerInfoChangedWithExclusions} from {@link #VERSION_INT} 2.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public void onPlayerInfoChanged(int seq, Bundle playerInfoBundle, boolean isTimelineExcluded) {
|
public void onPlayerInfoChanged(int seq, Bundle playerInfoBundle, boolean isTimelineExcluded) {
|
||||||
|
onPlayerInfoChangedWithExclusions(
|
||||||
|
seq,
|
||||||
|
playerInfoBundle,
|
||||||
|
new BundlingExclusions(isTimelineExcluded, /* areCurrentTracksExcluded= */ true)
|
||||||
|
.toBundle());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Added in {@link #VERSION_INT} 2. */
|
||||||
|
@Override
|
||||||
|
public void onPlayerInfoChangedWithExclusions(
|
||||||
|
int seq, Bundle playerInfoBundle, Bundle playerInfoExclusions) {
|
||||||
PlayerInfo playerInfo;
|
PlayerInfo playerInfo;
|
||||||
try {
|
try {
|
||||||
playerInfo = PlayerInfo.CREATOR.fromBundle(playerInfoBundle);
|
playerInfo = PlayerInfo.CREATOR.fromBundle(playerInfoBundle);
|
||||||
@ -178,8 +194,15 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for PlayerInfo", e);
|
Log.w(TAG, "Ignoring malformed Bundle for PlayerInfo", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
BundlingExclusions bundlingExclusions;
|
||||||
|
try {
|
||||||
|
bundlingExclusions = BundlingExclusions.CREATOR.fromBundle(playerInfoExclusions);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Bundle for BundlingExclusions", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatchControllerTaskOnHandler(
|
dispatchControllerTaskOnHandler(
|
||||||
controller -> controller.onPlayerInfoChanged(playerInfo, isTimelineExcluded));
|
controller -> controller.onPlayerInfoChanged(playerInfo, bundlingExclusions));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1136,7 +1136,8 @@ public class MediaSession {
|
|||||||
boolean excludeMediaItemsMetadata,
|
boolean excludeMediaItemsMetadata,
|
||||||
boolean excludeCues,
|
boolean excludeCues,
|
||||||
boolean excludeTimeline,
|
boolean excludeTimeline,
|
||||||
boolean excludeTracks)
|
boolean excludeTracks,
|
||||||
|
int controllerInterfaceVersion)
|
||||||
throws RemoteException {}
|
throws RemoteException {}
|
||||||
|
|
||||||
default void onPeriodicSessionPositionInfoChanged(
|
default void onPeriodicSessionPositionInfoChanged(
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.session;
|
package androidx.media3.session;
|
||||||
|
|
||||||
|
import static androidx.media3.common.Player.COMMAND_GET_MEDIA_ITEMS_METADATA;
|
||||||
|
import static androidx.media3.common.Player.COMMAND_GET_TEXT;
|
||||||
|
import static androidx.media3.common.Player.COMMAND_GET_TIMELINE;
|
||||||
|
import static androidx.media3.common.Player.COMMAND_GET_TRACKS;
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||||
import static androidx.media3.common.util.Util.castNonNull;
|
import static androidx.media3.common.util.Util.castNonNull;
|
||||||
@ -274,7 +278,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
}
|
}
|
||||||
|
|
||||||
playerInfo = newPlayerWrapper.createPlayerInfoForBundling();
|
playerInfo = newPlayerWrapper.createPlayerInfoForBundling();
|
||||||
onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ false);
|
onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ false, /* excludeTracks= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void release() {
|
public void release() {
|
||||||
@ -374,7 +379,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
controller,
|
controller,
|
||||||
(callback, seq) ->
|
(callback, seq) ->
|
||||||
callback.onAvailableCommandsChangedFromSession(seq, sessionCommands, playerCommands));
|
callback.onAvailableCommandsChangedFromSession(seq, sessionCommands, playerCommands));
|
||||||
onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ false);
|
onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ false, /* excludeTracks= */ false);
|
||||||
} else {
|
} else {
|
||||||
sessionLegacyStub
|
sessionLegacyStub
|
||||||
.getConnectedControllersManager()
|
.getConnectedControllersManager()
|
||||||
@ -387,7 +393,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
(controller, seq) -> controller.sendCustomCommand(seq, command, args));
|
(controller, seq) -> controller.sendCustomCommand(seq, command, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispatchOnPlayerInfoChanged(PlayerInfo playerInfo, boolean excludeTimeline) {
|
private void dispatchOnPlayerInfoChanged(
|
||||||
|
PlayerInfo playerInfo, boolean excludeTimeline, boolean excludeTracks) {
|
||||||
|
|
||||||
List<ControllerInfo> controllers =
|
List<ControllerInfo> controllers =
|
||||||
sessionStub.getConnectedControllersManager().getConnectedControllers();
|
sessionStub.getConnectedControllersManager().getConnectedControllers();
|
||||||
@ -395,8 +402,9 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
ControllerInfo controller = controllers.get(i);
|
ControllerInfo controller = controllers.get(i);
|
||||||
try {
|
try {
|
||||||
int seq;
|
int seq;
|
||||||
SequencedFutureManager manager =
|
ConnectedControllersManager<IBinder> controllersManager =
|
||||||
sessionStub.getConnectedControllersManager().getSequencedFutureManager(controller);
|
sessionStub.getConnectedControllersManager();
|
||||||
|
SequencedFutureManager manager = controllersManager.getSequencedFutureManager(controller);
|
||||||
if (manager != null) {
|
if (manager != null) {
|
||||||
seq = manager.obtainNextSequenceNumber();
|
seq = manager.obtainNextSequenceNumber();
|
||||||
} else {
|
} else {
|
||||||
@ -410,19 +418,18 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
.onPlayerInfoChanged(
|
.onPlayerInfoChanged(
|
||||||
seq,
|
seq,
|
||||||
playerInfo,
|
playerInfo,
|
||||||
/* excludeMediaItems= */ !sessionStub
|
/* excludeMediaItems= */ !controllersManager.isPlayerCommandAvailable(
|
||||||
.getConnectedControllersManager()
|
controller, COMMAND_GET_TIMELINE),
|
||||||
.isPlayerCommandAvailable(controller, Player.COMMAND_GET_TIMELINE),
|
/* excludeMediaItemsMetadata= */ !controllersManager.isPlayerCommandAvailable(
|
||||||
/* excludeMediaItemsMetadata= */ !sessionStub
|
controller, COMMAND_GET_MEDIA_ITEMS_METADATA),
|
||||||
.getConnectedControllersManager()
|
/* excludeCues= */ !controllersManager.isPlayerCommandAvailable(
|
||||||
.isPlayerCommandAvailable(controller, Player.COMMAND_GET_MEDIA_ITEMS_METADATA),
|
controller, COMMAND_GET_TEXT),
|
||||||
/* excludeCues= */ !sessionStub
|
excludeTimeline
|
||||||
.getConnectedControllersManager()
|
|| !controllersManager.isPlayerCommandAvailable(
|
||||||
.isPlayerCommandAvailable(controller, Player.COMMAND_GET_TEXT),
|
controller, COMMAND_GET_TIMELINE),
|
||||||
excludeTimeline,
|
excludeTracks
|
||||||
/* excludeTracks= */ !sessionStub
|
|| !controllersManager.isPlayerCommandAvailable(controller, COMMAND_GET_TRACKS),
|
||||||
.getConnectedControllersManager()
|
controller.getInterfaceVersion());
|
||||||
.isPlayerCommandAvailable(controller, Player.COMMAND_GET_TRACKS));
|
|
||||||
} catch (DeadObjectException e) {
|
} catch (DeadObjectException e) {
|
||||||
onDeadObjectException(controller);
|
onDeadObjectException(controller);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
@ -745,7 +752,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithPlayerError(error);
|
session.playerInfo = session.playerInfo.copyWithPlayerError(error);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onPlayerError(seq, error));
|
(callback, seq) -> callback.onPlayerError(seq, error));
|
||||||
}
|
}
|
||||||
@ -765,7 +773,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
// Note: OK to omit mediaItem here, because PlayerInfo changed message will copy playerInfo
|
// Note: OK to omit mediaItem here, because PlayerInfo changed message will copy playerInfo
|
||||||
// with sessionPositionInfo, which includes current window index.
|
// with sessionPositionInfo, which includes current window index.
|
||||||
session.playerInfo = session.playerInfo.copyWithMediaItemTransitionReason(reason);
|
session.playerInfo = session.playerInfo.copyWithMediaItemTransitionReason(reason);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onMediaItemTransition(seq, mediaItem, reason));
|
(callback, seq) -> callback.onMediaItemTransition(seq, mediaItem, reason));
|
||||||
}
|
}
|
||||||
@ -785,7 +794,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
session.playerInfo =
|
session.playerInfo =
|
||||||
session.playerInfo.copyWithPlayWhenReady(
|
session.playerInfo.copyWithPlayWhenReady(
|
||||||
playWhenReady, reason, session.playerInfo.playbackSuppressionReason);
|
playWhenReady, reason, session.playerInfo.playbackSuppressionReason);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onPlayWhenReadyChanged(seq, playWhenReady, reason));
|
(callback, seq) -> callback.onPlayWhenReadyChanged(seq, playWhenReady, reason));
|
||||||
}
|
}
|
||||||
@ -806,7 +816,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
session.playerInfo.playWhenReady,
|
session.playerInfo.playWhenReady,
|
||||||
session.playerInfo.playWhenReadyChangedReason,
|
session.playerInfo.playWhenReadyChangedReason,
|
||||||
reason);
|
reason);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onPlaybackSuppressionReasonChanged(seq, reason));
|
(callback, seq) -> callback.onPlaybackSuppressionReasonChanged(seq, reason));
|
||||||
}
|
}
|
||||||
@ -824,7 +835,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
}
|
}
|
||||||
session.playerInfo =
|
session.playerInfo =
|
||||||
session.playerInfo.copyWithPlaybackState(playbackState, player.getPlayerError());
|
session.playerInfo.copyWithPlaybackState(playbackState, player.getPlayerError());
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> {
|
(callback, seq) -> {
|
||||||
callback.onPlaybackStateChanged(seq, playbackState, player.getPlayerError());
|
callback.onPlaybackStateChanged(seq, playbackState, player.getPlayerError());
|
||||||
@ -843,7 +855,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithIsPlaying(isPlaying);
|
session.playerInfo = session.playerInfo.copyWithIsPlaying(isPlaying);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onIsPlayingChanged(seq, isPlaying));
|
(callback, seq) -> callback.onIsPlayingChanged(seq, isPlaying));
|
||||||
}
|
}
|
||||||
@ -860,7 +873,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithIsLoading(isLoading);
|
session.playerInfo = session.playerInfo.copyWithIsLoading(isLoading);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onIsLoadingChanged(seq, isLoading));
|
(callback, seq) -> callback.onIsLoadingChanged(seq, isLoading));
|
||||||
}
|
}
|
||||||
@ -880,7 +894,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
|
|
||||||
session.playerInfo =
|
session.playerInfo =
|
||||||
session.playerInfo.copyWithPositionInfos(oldPosition, newPosition, reason);
|
session.playerInfo.copyWithPositionInfos(oldPosition, newPosition, reason);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) ->
|
(callback, seq) ->
|
||||||
callback.onPositionDiscontinuity(seq, oldPosition, newPosition, reason));
|
callback.onPositionDiscontinuity(seq, oldPosition, newPosition, reason));
|
||||||
@ -898,7 +913,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithPlaybackParameters(playbackParameters);
|
session.playerInfo = session.playerInfo.copyWithPlaybackParameters(playbackParameters);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onPlaybackParametersChanged(seq, playbackParameters));
|
(callback, seq) -> callback.onPlaybackParametersChanged(seq, playbackParameters));
|
||||||
}
|
}
|
||||||
@ -915,7 +931,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithSeekBackIncrement(seekBackIncrementMs);
|
session.playerInfo = session.playerInfo.copyWithSeekBackIncrement(seekBackIncrementMs);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onSeekBackIncrementChanged(seq, seekBackIncrementMs));
|
(callback, seq) -> callback.onSeekBackIncrementChanged(seq, seekBackIncrementMs));
|
||||||
}
|
}
|
||||||
@ -932,7 +949,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithSeekForwardIncrement(seekForwardIncrementMs);
|
session.playerInfo = session.playerInfo.copyWithSeekForwardIncrement(seekForwardIncrementMs);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onSeekForwardIncrementChanged(seq, seekForwardIncrementMs));
|
(callback, seq) -> callback.onSeekForwardIncrementChanged(seq, seekForwardIncrementMs));
|
||||||
}
|
}
|
||||||
@ -951,7 +969,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
session.playerInfo =
|
session.playerInfo =
|
||||||
session.playerInfo.copyWithTimelineAndSessionPositionInfo(
|
session.playerInfo.copyWithTimelineAndSessionPositionInfo(
|
||||||
timeline, player.createSessionPositionInfoForBundling());
|
timeline, player.createSessionPositionInfoForBundling());
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ false);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ false, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onTimelineChanged(seq, timeline, reason));
|
(callback, seq) -> callback.onTimelineChanged(seq, timeline, reason));
|
||||||
}
|
}
|
||||||
@ -964,7 +983,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
}
|
}
|
||||||
session.verifyApplicationThread();
|
session.verifyApplicationThread();
|
||||||
session.playerInfo = session.playerInfo.copyWithPlaylistMetadata(playlistMetadata);
|
session.playerInfo = session.playerInfo.copyWithPlaylistMetadata(playlistMetadata);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onPlaylistMetadataChanged(seq, playlistMetadata));
|
(callback, seq) -> callback.onPlaylistMetadataChanged(seq, playlistMetadata));
|
||||||
}
|
}
|
||||||
@ -981,7 +1001,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithRepeatMode(repeatMode);
|
session.playerInfo = session.playerInfo.copyWithRepeatMode(repeatMode);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onRepeatModeChanged(seq, repeatMode));
|
(callback, seq) -> callback.onRepeatModeChanged(seq, repeatMode));
|
||||||
}
|
}
|
||||||
@ -998,7 +1019,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithShuffleModeEnabled(shuffleModeEnabled);
|
session.playerInfo = session.playerInfo.copyWithShuffleModeEnabled(shuffleModeEnabled);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onShuffleModeEnabledChanged(seq, shuffleModeEnabled));
|
(callback, seq) -> callback.onShuffleModeEnabledChanged(seq, shuffleModeEnabled));
|
||||||
}
|
}
|
||||||
@ -1015,7 +1037,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithAudioAttributes(attributes);
|
session.playerInfo = session.playerInfo.copyWithAudioAttributes(attributes);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(controller, seq) -> controller.onAudioAttributesChanged(seq, attributes));
|
(controller, seq) -> controller.onAudioAttributesChanged(seq, attributes));
|
||||||
}
|
}
|
||||||
@ -1028,7 +1051,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
}
|
}
|
||||||
session.verifyApplicationThread();
|
session.verifyApplicationThread();
|
||||||
session.playerInfo = session.playerInfo.copyWithVideoSize(size);
|
session.playerInfo = session.playerInfo.copyWithVideoSize(size);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onVideoSizeChanged(seq, size));
|
(callback, seq) -> callback.onVideoSizeChanged(seq, size));
|
||||||
}
|
}
|
||||||
@ -1041,7 +1065,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
}
|
}
|
||||||
session.verifyApplicationThread();
|
session.verifyApplicationThread();
|
||||||
session.playerInfo = session.playerInfo.copyWithVolume(volume);
|
session.playerInfo = session.playerInfo.copyWithVolume(volume);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onVolumeChanged(seq, volume));
|
(callback, seq) -> callback.onVolumeChanged(seq, volume));
|
||||||
}
|
}
|
||||||
@ -1058,7 +1083,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = new PlayerInfo.Builder(session.playerInfo).setCues(cueGroup).build();
|
session.playerInfo = new PlayerInfo.Builder(session.playerInfo).setCues(cueGroup).build();
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1073,7 +1099,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithDeviceInfo(deviceInfo);
|
session.playerInfo = session.playerInfo.copyWithDeviceInfo(deviceInfo);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onDeviceInfoChanged(seq, deviceInfo));
|
(callback, seq) -> callback.onDeviceInfoChanged(seq, deviceInfo));
|
||||||
}
|
}
|
||||||
@ -1090,7 +1117,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithDeviceVolume(volume, muted);
|
session.playerInfo = session.playerInfo.copyWithDeviceVolume(volume, muted);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onDeviceVolumeChanged(seq, volume, muted));
|
(callback, seq) -> callback.onDeviceVolumeChanged(seq, volume, muted));
|
||||||
}
|
}
|
||||||
@ -1106,7 +1134,9 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ false);
|
boolean excludeTracks = !availableCommands.contains(COMMAND_GET_TRACKS);
|
||||||
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ false, excludeTracks);
|
||||||
session.dispatchRemoteControllerTaskWithoutReturn(
|
session.dispatchRemoteControllerTaskWithoutReturn(
|
||||||
(callback, seq) -> callback.onAvailableCommandsChangedFromPlayer(seq, availableCommands));
|
(callback, seq) -> callback.onAvailableCommandsChangedFromPlayer(seq, availableCommands));
|
||||||
|
|
||||||
@ -1128,7 +1158,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithCurrentTracks(tracks);
|
session.playerInfo = session.playerInfo.copyWithCurrentTracks(tracks);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ false);
|
||||||
session.dispatchRemoteControllerTaskWithoutReturn(
|
session.dispatchRemoteControllerTaskWithoutReturn(
|
||||||
(callback, seq) -> callback.onTracksChanged(seq, tracks));
|
(callback, seq) -> callback.onTracksChanged(seq, tracks));
|
||||||
}
|
}
|
||||||
@ -1145,7 +1176,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithTrackSelectionParameters(parameters);
|
session.playerInfo = session.playerInfo.copyWithTrackSelectionParameters(parameters);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskWithoutReturn(
|
session.dispatchRemoteControllerTaskWithoutReturn(
|
||||||
(callback, seq) -> callback.onTrackSelectionParametersChanged(seq, parameters));
|
(callback, seq) -> callback.onTrackSelectionParametersChanged(seq, parameters));
|
||||||
}
|
}
|
||||||
@ -1162,7 +1194,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.playerInfo = session.playerInfo.copyWithMediaMetadata(mediaMetadata);
|
session.playerInfo = session.playerInfo.copyWithMediaMetadata(mediaMetadata);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
session.dispatchRemoteControllerTaskToLegacyStub(
|
session.dispatchRemoteControllerTaskToLegacyStub(
|
||||||
(callback, seq) -> callback.onMediaMetadataChanged(seq, mediaMetadata));
|
(callback, seq) -> callback.onMediaMetadataChanged(seq, mediaMetadata));
|
||||||
}
|
}
|
||||||
@ -1190,7 +1223,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
}
|
}
|
||||||
session.playerInfo =
|
session.playerInfo =
|
||||||
session.playerInfo.copyWithMaxSeekToPreviousPositionMs(maxSeekToPreviousPositionMs);
|
session.playerInfo.copyWithMaxSeekToPreviousPositionMs(maxSeekToPreviousPositionMs);
|
||||||
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true);
|
session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(
|
||||||
|
/* excludeTimeline= */ true, /* excludeTracks= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -1224,10 +1258,12 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
private static final int MSG_PLAYER_INFO_CHANGED = 1;
|
private static final int MSG_PLAYER_INFO_CHANGED = 1;
|
||||||
|
|
||||||
private boolean excludeTimeline;
|
private boolean excludeTimeline;
|
||||||
|
private boolean excludeTracks;
|
||||||
|
|
||||||
public PlayerInfoChangedHandler(Looper looper) {
|
public PlayerInfoChangedHandler(Looper looper) {
|
||||||
super(looper);
|
super(looper);
|
||||||
excludeTimeline = true;
|
excludeTimeline = true;
|
||||||
|
excludeTracks = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1237,15 +1273,17 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
playerInfo.copyWithTimelineAndSessionPositionInfo(
|
playerInfo.copyWithTimelineAndSessionPositionInfo(
|
||||||
getPlayerWrapper().getCurrentTimeline(),
|
getPlayerWrapper().getCurrentTimeline(),
|
||||||
getPlayerWrapper().createSessionPositionInfoForBundling());
|
getPlayerWrapper().createSessionPositionInfoForBundling());
|
||||||
dispatchOnPlayerInfoChanged(playerInfo, excludeTimeline);
|
dispatchOnPlayerInfoChanged(playerInfo, excludeTimeline, excludeTracks);
|
||||||
excludeTimeline = true;
|
excludeTimeline = true;
|
||||||
|
excludeTracks = true;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Invalid message what=" + msg.what);
|
throw new IllegalStateException("Invalid message what=" + msg.what);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPlayerInfoChangedMessage(boolean excludeTimeline) {
|
public void sendPlayerInfoChangedMessage(boolean excludeTimeline, boolean excludeTracks) {
|
||||||
this.excludeTimeline = this.excludeTimeline && excludeTimeline;
|
this.excludeTimeline = this.excludeTimeline && excludeTimeline;
|
||||||
|
this.excludeTracks = this.excludeTracks && excludeTracks;
|
||||||
if (!onPlayerInfoChangedHandler.hasMessages(MSG_PLAYER_INFO_CHANGED)) {
|
if (!onPlayerInfoChangedHandler.hasMessages(MSG_PLAYER_INFO_CHANGED)) {
|
||||||
onPlayerInfoChangedHandler.sendEmptyMessage(MSG_PLAYER_INFO_CHANGED);
|
onPlayerInfoChangedHandler.sendEmptyMessage(MSG_PLAYER_INFO_CHANGED);
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ import androidx.media3.common.PlaybackParameters;
|
|||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.common.Rating;
|
import androidx.media3.common.Rating;
|
||||||
import androidx.media3.common.TrackSelectionParameters;
|
import androidx.media3.common.TrackSelectionParameters;
|
||||||
|
import androidx.media3.common.util.Assertions;
|
||||||
import androidx.media3.common.util.BundleableUtil;
|
import androidx.media3.common.util.BundleableUtil;
|
||||||
import androidx.media3.common.util.Consumer;
|
import androidx.media3.common.util.Consumer;
|
||||||
import androidx.media3.common.util.Log;
|
import androidx.media3.common.util.Log;
|
||||||
@ -1596,17 +1597,32 @@ import java.util.concurrent.ExecutionException;
|
|||||||
boolean excludeMediaItemsMetadata,
|
boolean excludeMediaItemsMetadata,
|
||||||
boolean excludeCues,
|
boolean excludeCues,
|
||||||
boolean excludeTimeline,
|
boolean excludeTimeline,
|
||||||
boolean excludeTracks)
|
boolean excludeTracks,
|
||||||
|
int controllerInterfaceVersion)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
iController.onPlayerInfoChanged(
|
Assertions.checkState(controllerInterfaceVersion != 0);
|
||||||
sequenceNumber,
|
if (controllerInterfaceVersion >= 2) {
|
||||||
playerInfo.toBundle(
|
iController.onPlayerInfoChangedWithExclusions(
|
||||||
excludeMediaItems,
|
sequenceNumber,
|
||||||
excludeMediaItemsMetadata,
|
playerInfo.toBundle(
|
||||||
excludeCues,
|
excludeMediaItems,
|
||||||
excludeTimeline,
|
excludeMediaItemsMetadata,
|
||||||
excludeTracks),
|
excludeCues,
|
||||||
/* isTimelineExcluded= */ excludeTimeline);
|
excludeTimeline,
|
||||||
|
excludeTracks),
|
||||||
|
new PlayerInfo.BundlingExclusions(excludeTimeline, excludeTracks).toBundle());
|
||||||
|
} else {
|
||||||
|
//noinspection deprecation
|
||||||
|
iController.onPlayerInfoChanged(
|
||||||
|
sequenceNumber,
|
||||||
|
playerInfo.toBundle(
|
||||||
|
excludeMediaItems,
|
||||||
|
excludeMediaItemsMetadata,
|
||||||
|
excludeCues,
|
||||||
|
excludeTimeline,
|
||||||
|
/* excludeTracks= */ true),
|
||||||
|
excludeTimeline);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -62,6 +62,7 @@ import android.support.v4.media.session.MediaSessionCompat.QueueItem;
|
|||||||
import android.support.v4.media.session.PlaybackStateCompat;
|
import android.support.v4.media.session.PlaybackStateCompat;
|
||||||
import android.support.v4.media.session.PlaybackStateCompat.CustomAction;
|
import android.support.v4.media.session.PlaybackStateCompat.CustomAction;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Pair;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media.AudioAttributesCompat;
|
import androidx.media.AudioAttributesCompat;
|
||||||
import androidx.media.MediaBrowserServiceCompat.BrowserRoot;
|
import androidx.media.MediaBrowserServiceCompat.BrowserRoot;
|
||||||
@ -87,6 +88,7 @@ import androidx.media3.common.Timeline.Window;
|
|||||||
import androidx.media3.common.util.Log;
|
import androidx.media3.common.util.Log;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.session.MediaLibraryService.LibraryParams;
|
import androidx.media3.session.MediaLibraryService.LibraryParams;
|
||||||
|
import androidx.media3.session.PlayerInfo.BundlingExclusions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -1288,6 +1290,46 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
return intersectCommandsBuilder.build();
|
return intersectCommandsBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges the excluded fields into the {@code newPlayerInfo} by taking the values of the {@code
|
||||||
|
* previousPlayerInfo} and taking into account the passed available commands.
|
||||||
|
*
|
||||||
|
* @param oldPlayerInfo The old {@link PlayerInfo}.
|
||||||
|
* @param oldBundlingExclusions The bundling exlusions in the old {@link PlayerInfo}.
|
||||||
|
* @param newPlayerInfo The new {@link PlayerInfo}.
|
||||||
|
* @param newBundlingExclusions The bundling exlusions in the new {@link PlayerInfo}.
|
||||||
|
* @param availablePlayerCommands The available commands to take into account when merging.
|
||||||
|
* @return A pair with the resulting {@link PlayerInfo} and {@link BundlingExclusions}.
|
||||||
|
*/
|
||||||
|
public static Pair<PlayerInfo, BundlingExclusions> mergePlayerInfo(
|
||||||
|
PlayerInfo oldPlayerInfo,
|
||||||
|
BundlingExclusions oldBundlingExclusions,
|
||||||
|
PlayerInfo newPlayerInfo,
|
||||||
|
BundlingExclusions newBundlingExclusions,
|
||||||
|
Commands availablePlayerCommands) {
|
||||||
|
PlayerInfo mergedPlayerInfo = newPlayerInfo;
|
||||||
|
BundlingExclusions mergedBundlingExclusions = newBundlingExclusions;
|
||||||
|
if (newBundlingExclusions.isTimelineExcluded
|
||||||
|
&& availablePlayerCommands.contains(Player.COMMAND_GET_TIMELINE)
|
||||||
|
&& !oldBundlingExclusions.isTimelineExcluded) {
|
||||||
|
// Use the previous timeline if it is excluded in the most recent update.
|
||||||
|
mergedPlayerInfo = mergedPlayerInfo.copyWithTimeline(oldPlayerInfo.timeline);
|
||||||
|
mergedBundlingExclusions =
|
||||||
|
new BundlingExclusions(
|
||||||
|
/* isTimelineExcluded= */ false, mergedBundlingExclusions.areCurrentTracksExcluded);
|
||||||
|
}
|
||||||
|
if (newBundlingExclusions.areCurrentTracksExcluded
|
||||||
|
&& availablePlayerCommands.contains(Player.COMMAND_GET_TRACKS)
|
||||||
|
&& !oldBundlingExclusions.areCurrentTracksExcluded) {
|
||||||
|
// Use the previous tracks if it is excluded in the most recent update.
|
||||||
|
mergedPlayerInfo = mergedPlayerInfo.copyWithCurrentTracks(oldPlayerInfo.currentTracks);
|
||||||
|
mergedBundlingExclusions =
|
||||||
|
new BundlingExclusions(
|
||||||
|
mergedBundlingExclusions.isTimelineExcluded, /* areCurrentTracksExcluded= */ false);
|
||||||
|
}
|
||||||
|
return new Pair<>(mergedPlayerInfo, mergedBundlingExclusions);
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] convertToByteArray(Bitmap bitmap) throws IOException {
|
private static byte[] convertToByteArray(Bitmap bitmap) throws IOException {
|
||||||
try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
|
try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, /* ignored */ 0, stream);
|
bitmap.compress(Bitmap.CompressFormat.PNG, /* ignored */ 0, stream);
|
||||||
|
@ -66,6 +66,10 @@ import java.lang.annotation.Target;
|
|||||||
*/
|
*/
|
||||||
public static class BundlingExclusions implements Bundleable {
|
public static class BundlingExclusions implements Bundleable {
|
||||||
|
|
||||||
|
/** Bundling exclusions with no exclusions. */
|
||||||
|
public static final BundlingExclusions NONE =
|
||||||
|
new BundlingExclusions(
|
||||||
|
/* isTimelineExcluded= */ false, /* areCurrentTracksExcluded= */ false);
|
||||||
/** Whether the {@linkplain PlayerInfo#timeline timeline} is excluded. */
|
/** Whether the {@linkplain PlayerInfo#timeline timeline} is excluded. */
|
||||||
public final boolean isTimelineExcluded;
|
public final boolean isTimelineExcluded;
|
||||||
/** Whether the {@linkplain PlayerInfo#currentTracks current tracks} are excluded. */
|
/** Whether the {@linkplain PlayerInfo#currentTracks current tracks} are excluded. */
|
||||||
|
@ -1052,8 +1052,8 @@ public class MediaControllerListenerTest {
|
|||||||
MediaController controller = controllerTestRule.createController(remoteSession.getToken());
|
MediaController controller = controllerTestRule.createController(remoteSession.getToken());
|
||||||
AtomicReference<Tracks> changedCurrentTracksFromParamRef = new AtomicReference<>();
|
AtomicReference<Tracks> changedCurrentTracksFromParamRef = new AtomicReference<>();
|
||||||
AtomicReference<Tracks> changedCurrentTracksFromGetterRef = new AtomicReference<>();
|
AtomicReference<Tracks> changedCurrentTracksFromGetterRef = new AtomicReference<>();
|
||||||
AtomicReference<Tracks> changedCurrentTracksFromOnEventsRef = new AtomicReference<>();
|
List<Tracks> changedCurrentTracksFromOnEvents = new ArrayList<>();
|
||||||
AtomicReference<Player.Events> eventsRef = new AtomicReference<>();
|
List<Player.Events> capturedEvents = new ArrayList<>();
|
||||||
CountDownLatch latch = new CountDownLatch(2);
|
CountDownLatch latch = new CountDownLatch(2);
|
||||||
Player.Listener listener =
|
Player.Listener listener =
|
||||||
new Player.Listener() {
|
new Player.Listener() {
|
||||||
@ -1061,13 +1061,12 @@ public class MediaControllerListenerTest {
|
|||||||
public void onTracksChanged(Tracks currentTracks) {
|
public void onTracksChanged(Tracks currentTracks) {
|
||||||
changedCurrentTracksFromParamRef.set(currentTracks);
|
changedCurrentTracksFromParamRef.set(currentTracks);
|
||||||
changedCurrentTracksFromGetterRef.set(controller.getCurrentTracks());
|
changedCurrentTracksFromGetterRef.set(controller.getCurrentTracks());
|
||||||
latch.countDown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvents(Player player, Player.Events events) {
|
public void onEvents(Player player, Player.Events events) {
|
||||||
eventsRef.set(events);
|
capturedEvents.add(events);
|
||||||
changedCurrentTracksFromOnEventsRef.set(player.getCurrentTracks());
|
changedCurrentTracksFromOnEvents.add(player.getCurrentTracks());
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1081,13 +1080,22 @@ public class MediaControllerListenerTest {
|
|||||||
});
|
});
|
||||||
|
|
||||||
player.notifyTracksChanged(currentTracks);
|
player.notifyTracksChanged(currentTracks);
|
||||||
|
player.notifyIsLoadingChanged(true);
|
||||||
|
|
||||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||||
assertThat(initialCurrentTracksRef.get()).isEqualTo(Tracks.EMPTY);
|
assertThat(initialCurrentTracksRef.get()).isEqualTo(Tracks.EMPTY);
|
||||||
assertThat(changedCurrentTracksFromParamRef.get()).isEqualTo(currentTracks);
|
assertThat(changedCurrentTracksFromParamRef.get()).isEqualTo(currentTracks);
|
||||||
assertThat(changedCurrentTracksFromGetterRef.get()).isEqualTo(currentTracks);
|
assertThat(changedCurrentTracksFromGetterRef.get()).isEqualTo(currentTracks);
|
||||||
assertThat(changedCurrentTracksFromOnEventsRef.get()).isEqualTo(currentTracks);
|
assertThat(capturedEvents).hasSize(2);
|
||||||
assertThat(getEventsAsList(eventsRef.get())).containsExactly(Player.EVENT_TRACKS_CHANGED);
|
assertThat(getEventsAsList(capturedEvents.get(0))).containsExactly(Player.EVENT_TRACKS_CHANGED);
|
||||||
|
assertThat(getEventsAsList(capturedEvents.get(1)))
|
||||||
|
.containsExactly(Player.EVENT_IS_LOADING_CHANGED);
|
||||||
|
assertThat(changedCurrentTracksFromOnEvents).hasSize(2);
|
||||||
|
assertThat(changedCurrentTracksFromOnEvents.get(0)).isEqualTo(currentTracks);
|
||||||
|
assertThat(changedCurrentTracksFromOnEvents.get(1)).isEqualTo(currentTracks);
|
||||||
|
// Assert that an equal instance is not re-sent over the binder.
|
||||||
|
assertThat(changedCurrentTracksFromOnEvents.get(0))
|
||||||
|
.isSameInstanceAs(changedCurrentTracksFromOnEvents.get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1142,6 +1150,9 @@ public class MediaControllerListenerTest {
|
|||||||
assertThat(capturedCurrentTracks).containsExactly(Tracks.EMPTY);
|
assertThat(capturedCurrentTracks).containsExactly(Tracks.EMPTY);
|
||||||
assertThat(initialCurrentTracksWithCommandAvailable.get().getGroups()).hasSize(1);
|
assertThat(initialCurrentTracksWithCommandAvailable.get().getGroups()).hasSize(1);
|
||||||
assertThat(capturedCurrentTracksWithCommandAvailable.get().getGroups()).hasSize(1);
|
assertThat(capturedCurrentTracksWithCommandAvailable.get().getGroups()).hasSize(1);
|
||||||
|
// Assert that an equal instance is not re-sent over the binder.
|
||||||
|
assertThat(initialCurrentTracksWithCommandAvailable.get())
|
||||||
|
.isSameInstanceAs(capturedCurrentTracksWithCommandAvailable.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1181,6 +1192,7 @@ public class MediaControllerListenerTest {
|
|||||||
availableCommands.get().buildUpon().remove(Player.COMMAND_GET_TRACKS).build());
|
availableCommands.get().buildUpon().remove(Player.COMMAND_GET_TRACKS).build());
|
||||||
|
|
||||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||||
|
assertThat(capturedCurrentTracks).hasSize(2);
|
||||||
assertThat(capturedCurrentTracks.get(0).getGroups()).hasSize(1);
|
assertThat(capturedCurrentTracks.get(0).getGroups()).hasSize(1);
|
||||||
assertThat(capturedCurrentTracks.get(1)).isEqualTo(Tracks.EMPTY);
|
assertThat(capturedCurrentTracks.get(1)).isEqualTo(Tracks.EMPTY);
|
||||||
}
|
}
|
||||||
@ -2203,7 +2215,7 @@ public class MediaControllerListenerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onTimelineChanged_emptyMediaItemAndMediaMetadata_whenCommandUnavailableFromPlayer()
|
public void onTimelineChanged_playerCommandUnavailable_emptyTimelineMediaItemAndMetadata()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
int testMediaItemsSize = 2;
|
int testMediaItemsSize = 2;
|
||||||
List<MediaItem> testMediaItemList = MediaTestUtils.createMediaItems(testMediaItemsSize);
|
List<MediaItem> testMediaItemList = MediaTestUtils.createMediaItems(testMediaItemsSize);
|
||||||
@ -2217,7 +2229,7 @@ public class MediaControllerListenerTest {
|
|||||||
AtomicReference<Timeline> timelineFromGetterRef = new AtomicReference<>();
|
AtomicReference<Timeline> timelineFromGetterRef = new AtomicReference<>();
|
||||||
List<Timeline> onEventsTimelines = new ArrayList<>();
|
List<Timeline> onEventsTimelines = new ArrayList<>();
|
||||||
AtomicReference<MediaMetadata> metadataFromGetterRef = new AtomicReference<>();
|
AtomicReference<MediaMetadata> metadataFromGetterRef = new AtomicReference<>();
|
||||||
AtomicReference<MediaItem> currentMediaItemGetterRef = new AtomicReference<>();
|
AtomicReference<Boolean> isCurrentMediaItemNullRef = new AtomicReference<>();
|
||||||
List<Player.Events> eventsList = new ArrayList<>();
|
List<Player.Events> eventsList = new ArrayList<>();
|
||||||
Player.Listener listener =
|
Player.Listener listener =
|
||||||
new Player.Listener() {
|
new Player.Listener() {
|
||||||
@ -2226,7 +2238,7 @@ public class MediaControllerListenerTest {
|
|||||||
timelineFromParamRef.set(timeline);
|
timelineFromParamRef.set(timeline);
|
||||||
timelineFromGetterRef.set(controller.getCurrentTimeline());
|
timelineFromGetterRef.set(controller.getCurrentTimeline());
|
||||||
metadataFromGetterRef.set(controller.getMediaMetadata());
|
metadataFromGetterRef.set(controller.getMediaMetadata());
|
||||||
currentMediaItemGetterRef.set(controller.getCurrentMediaItem());
|
isCurrentMediaItemNullRef.set(controller.getCurrentMediaItem() == null);
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2244,24 +2256,7 @@ public class MediaControllerListenerTest {
|
|||||||
remoteSession.getMockPlayer().notifyAvailableCommandsChanged(commandsWithoutGetTimeline);
|
remoteSession.getMockPlayer().notifyAvailableCommandsChanged(commandsWithoutGetTimeline);
|
||||||
|
|
||||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||||
assertThat(timelineFromParamRef.get().getWindowCount()).isEqualTo(testMediaItemsSize);
|
assertThat(timelineFromParamRef.get()).isEqualTo(Timeline.EMPTY);
|
||||||
for (int i = 0; i < timelineFromParamRef.get().getWindowCount(); i++) {
|
|
||||||
assertThat(
|
|
||||||
timelineFromParamRef
|
|
||||||
.get()
|
|
||||||
.getWindow(/* windowIndex= */ i, new Timeline.Window())
|
|
||||||
.mediaItem)
|
|
||||||
.isEqualTo(MediaItem.EMPTY);
|
|
||||||
}
|
|
||||||
assertThat(timelineFromGetterRef.get().getWindowCount()).isEqualTo(testMediaItemsSize);
|
|
||||||
for (int i = 0; i < timelineFromGetterRef.get().getWindowCount(); i++) {
|
|
||||||
assertThat(
|
|
||||||
timelineFromGetterRef
|
|
||||||
.get()
|
|
||||||
.getWindow(/* windowIndex= */ i, new Timeline.Window())
|
|
||||||
.mediaItem)
|
|
||||||
.isEqualTo(MediaItem.EMPTY);
|
|
||||||
}
|
|
||||||
assertThat(onEventsTimelines).hasSize(2);
|
assertThat(onEventsTimelines).hasSize(2);
|
||||||
for (int i = 0; i < onEventsTimelines.get(1).getWindowCount(); i++) {
|
for (int i = 0; i < onEventsTimelines.get(1).getWindowCount(); i++) {
|
||||||
assertThat(
|
assertThat(
|
||||||
@ -2272,15 +2267,16 @@ public class MediaControllerListenerTest {
|
|||||||
.isEqualTo(MediaItem.EMPTY);
|
.isEqualTo(MediaItem.EMPTY);
|
||||||
}
|
}
|
||||||
assertThat(metadataFromGetterRef.get()).isEqualTo(MediaMetadata.EMPTY);
|
assertThat(metadataFromGetterRef.get()).isEqualTo(MediaMetadata.EMPTY);
|
||||||
assertThat(currentMediaItemGetterRef.get()).isEqualTo(MediaItem.EMPTY);
|
assertThat(isCurrentMediaItemNullRef.get()).isTrue();
|
||||||
assertThat(eventsList).hasSize(2);
|
assertThat(eventsList).hasSize(2);
|
||||||
assertThat(getEventsAsList(eventsList.get(0)))
|
assertThat(getEventsAsList(eventsList.get(0)))
|
||||||
.containsExactly(Player.EVENT_AVAILABLE_COMMANDS_CHANGED);
|
.containsExactly(Player.EVENT_AVAILABLE_COMMANDS_CHANGED);
|
||||||
assertThat(getEventsAsList(eventsList.get(1))).contains(Player.EVENT_TIMELINE_CHANGED);
|
assertThat(getEventsAsList(eventsList.get(1)))
|
||||||
|
.containsExactly(Player.EVENT_TIMELINE_CHANGED, Player.EVENT_MEDIA_ITEM_TRANSITION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onTimelineChanged_emptyMediaItemAndMediaMetadata_whenCommandUnavailableFromSession()
|
public void onTimelineChanged_sessionCommandUnavailable_emptyTimelineMediaItemAndMetadata()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
int testMediaItemsSize = 2;
|
int testMediaItemsSize = 2;
|
||||||
List<MediaItem> testMediaItemList = MediaTestUtils.createMediaItems(testMediaItemsSize);
|
List<MediaItem> testMediaItemList = MediaTestUtils.createMediaItems(testMediaItemsSize);
|
||||||
@ -2293,7 +2289,7 @@ public class MediaControllerListenerTest {
|
|||||||
AtomicReference<Timeline> timelineFromParamRef = new AtomicReference<>();
|
AtomicReference<Timeline> timelineFromParamRef = new AtomicReference<>();
|
||||||
AtomicReference<Timeline> timelineFromGetterRef = new AtomicReference<>();
|
AtomicReference<Timeline> timelineFromGetterRef = new AtomicReference<>();
|
||||||
AtomicReference<MediaMetadata> metadataFromGetterRef = new AtomicReference<>();
|
AtomicReference<MediaMetadata> metadataFromGetterRef = new AtomicReference<>();
|
||||||
AtomicReference<MediaItem> currentMediaItemGetterRef = new AtomicReference<>();
|
AtomicReference<Boolean> isCurrentMediaItemNullRef = new AtomicReference<>();
|
||||||
List<Player.Events> eventsList = new ArrayList<>();
|
List<Player.Events> eventsList = new ArrayList<>();
|
||||||
Player.Listener listener =
|
Player.Listener listener =
|
||||||
new Player.Listener() {
|
new Player.Listener() {
|
||||||
@ -2302,7 +2298,7 @@ public class MediaControllerListenerTest {
|
|||||||
timelineFromParamRef.set(timeline);
|
timelineFromParamRef.set(timeline);
|
||||||
timelineFromGetterRef.set(controller.getCurrentTimeline());
|
timelineFromGetterRef.set(controller.getCurrentTimeline());
|
||||||
metadataFromGetterRef.set(controller.getMediaMetadata());
|
metadataFromGetterRef.set(controller.getMediaMetadata());
|
||||||
currentMediaItemGetterRef.set(controller.getCurrentMediaItem());
|
isCurrentMediaItemNullRef.set(controller.getCurrentMediaItem() == null);
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2319,30 +2315,14 @@ public class MediaControllerListenerTest {
|
|||||||
remoteSession.setAvailableCommands(SessionCommands.EMPTY, commandsWithoutGetTimeline);
|
remoteSession.setAvailableCommands(SessionCommands.EMPTY, commandsWithoutGetTimeline);
|
||||||
|
|
||||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||||
assertThat(timelineFromParamRef.get().getWindowCount()).isEqualTo(testMediaItemsSize);
|
assertThat(timelineFromParamRef.get()).isEqualTo(Timeline.EMPTY);
|
||||||
for (int i = 0; i < timelineFromParamRef.get().getWindowCount(); i++) {
|
|
||||||
assertThat(
|
|
||||||
timelineFromParamRef
|
|
||||||
.get()
|
|
||||||
.getWindow(/* windowIndex= */ i, new Timeline.Window())
|
|
||||||
.mediaItem)
|
|
||||||
.isEqualTo(MediaItem.EMPTY);
|
|
||||||
}
|
|
||||||
assertThat(timelineFromGetterRef.get().getWindowCount()).isEqualTo(testMediaItemsSize);
|
|
||||||
for (int i = 0; i < timelineFromGetterRef.get().getWindowCount(); i++) {
|
|
||||||
assertThat(
|
|
||||||
timelineFromGetterRef
|
|
||||||
.get()
|
|
||||||
.getWindow(/* windowIndex= */ i, new Timeline.Window())
|
|
||||||
.mediaItem)
|
|
||||||
.isEqualTo(MediaItem.EMPTY);
|
|
||||||
}
|
|
||||||
assertThat(metadataFromGetterRef.get()).isEqualTo(MediaMetadata.EMPTY);
|
assertThat(metadataFromGetterRef.get()).isEqualTo(MediaMetadata.EMPTY);
|
||||||
assertThat(currentMediaItemGetterRef.get()).isEqualTo(MediaItem.EMPTY);
|
assertThat(isCurrentMediaItemNullRef.get()).isTrue();
|
||||||
assertThat(eventsList).hasSize(2);
|
assertThat(eventsList).hasSize(2);
|
||||||
assertThat(getEventsAsList(eventsList.get(0)))
|
assertThat(getEventsAsList(eventsList.get(0)))
|
||||||
.containsExactly(Player.EVENT_AVAILABLE_COMMANDS_CHANGED);
|
.containsExactly(Player.EVENT_AVAILABLE_COMMANDS_CHANGED);
|
||||||
assertThat(getEventsAsList(eventsList.get(1))).contains(Player.EVENT_TIMELINE_CHANGED);
|
assertThat(getEventsAsList(eventsList.get(1)))
|
||||||
|
.containsExactly(Player.EVENT_TIMELINE_CHANGED, Player.EVENT_MEDIA_ITEM_TRANSITION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This also tests {@link MediaController#getAvailableCommands()}. */
|
/** This also tests {@link MediaController#getAvailableCommands()}. */
|
||||||
|
@ -20,6 +20,9 @@ import static android.support.v4.media.MediaBrowserCompat.MediaItem.FLAG_PLAYABL
|
|||||||
import static android.support.v4.media.MediaMetadataCompat.METADATA_KEY_DURATION;
|
import static android.support.v4.media.MediaMetadataCompat.METADATA_KEY_DURATION;
|
||||||
import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS;
|
import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS;
|
||||||
import static androidx.media.utils.MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS;
|
import static androidx.media.utils.MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS;
|
||||||
|
import static androidx.media3.common.MimeTypes.AUDIO_AAC;
|
||||||
|
import static androidx.media3.common.MimeTypes.VIDEO_H264;
|
||||||
|
import static androidx.media3.common.MimeTypes.VIDEO_H265;
|
||||||
import static androidx.media3.session.MediaConstants.EXTRA_KEY_ROOT_CHILDREN_BROWSABLE_ONLY;
|
import static androidx.media3.session.MediaConstants.EXTRA_KEY_ROOT_CHILDREN_BROWSABLE_ONLY;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
@ -36,11 +39,13 @@ import android.support.v4.media.RatingCompat;
|
|||||||
import android.support.v4.media.session.MediaControllerCompat;
|
import android.support.v4.media.session.MediaControllerCompat;
|
||||||
import android.support.v4.media.session.MediaSessionCompat;
|
import android.support.v4.media.session.MediaSessionCompat;
|
||||||
import android.support.v4.media.session.PlaybackStateCompat;
|
import android.support.v4.media.session.PlaybackStateCompat;
|
||||||
|
import android.util.Pair;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media.AudioAttributesCompat;
|
import androidx.media.AudioAttributesCompat;
|
||||||
import androidx.media.utils.MediaConstants;
|
import androidx.media.utils.MediaConstants;
|
||||||
import androidx.media3.common.AudioAttributes;
|
import androidx.media3.common.AudioAttributes;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.HeartRating;
|
import androidx.media3.common.HeartRating;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.MediaMetadata;
|
import androidx.media3.common.MediaMetadata;
|
||||||
@ -49,10 +54,15 @@ import androidx.media3.common.Player;
|
|||||||
import androidx.media3.common.Rating;
|
import androidx.media3.common.Rating;
|
||||||
import androidx.media3.common.StarRating;
|
import androidx.media3.common.StarRating;
|
||||||
import androidx.media3.common.ThumbRating;
|
import androidx.media3.common.ThumbRating;
|
||||||
|
import androidx.media3.common.Timeline;
|
||||||
|
import androidx.media3.common.TrackGroup;
|
||||||
|
import androidx.media3.common.Tracks;
|
||||||
|
import androidx.media3.session.PlayerInfo.BundlingExclusions;
|
||||||
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.SdkSuppress;
|
import androidx.test.filters.SdkSuppress;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -623,4 +633,134 @@ public final class MediaUtilsTest {
|
|||||||
state, /* metadataCompat= */ null, /* timeDiffMs= */ C.INDEX_UNSET);
|
state, /* metadataCompat= */ null, /* timeDiffMs= */ C.INDEX_UNSET);
|
||||||
assertThat(totalBufferedDurationMs).isEqualTo(testTotalBufferedDurationMs);
|
assertThat(totalBufferedDurationMs).isEqualTo(testTotalBufferedDurationMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mergePlayerInfo_timelineAndTracksExcluded_correctMerge() {
|
||||||
|
Timeline timeline =
|
||||||
|
new Timeline.RemotableTimeline(
|
||||||
|
ImmutableList.of(new Timeline.Window()),
|
||||||
|
ImmutableList.of(new Timeline.Period()),
|
||||||
|
/* shuffledWindowIndices= */ new int[] {0});
|
||||||
|
Tracks tracks =
|
||||||
|
new Tracks(
|
||||||
|
ImmutableList.of(
|
||||||
|
new Tracks.Group(
|
||||||
|
new TrackGroup(new Format.Builder().setSampleMimeType(AUDIO_AAC).build()),
|
||||||
|
/* adaptiveSupported= */ false,
|
||||||
|
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
|
||||||
|
/* trackSelected= */ new boolean[] {true}),
|
||||||
|
new Tracks.Group(
|
||||||
|
new TrackGroup(
|
||||||
|
new Format.Builder().setSampleMimeType(VIDEO_H264).build(),
|
||||||
|
new Format.Builder().setSampleMimeType(VIDEO_H265).build()),
|
||||||
|
/* adaptiveSupported= */ true,
|
||||||
|
new int[] {C.FORMAT_HANDLED, C.FORMAT_UNSUPPORTED_TYPE},
|
||||||
|
/* trackSelected= */ new boolean[] {false, true})));
|
||||||
|
PlayerInfo oldPlayerInfo =
|
||||||
|
PlayerInfo.DEFAULT.copyWithCurrentTracks(tracks).copyWithTimeline(timeline);
|
||||||
|
PlayerInfo newPlayerInfo = PlayerInfo.DEFAULT;
|
||||||
|
Player.Commands availableCommands =
|
||||||
|
Player.Commands.EMPTY
|
||||||
|
.buildUpon()
|
||||||
|
.add(Player.COMMAND_GET_TIMELINE)
|
||||||
|
.add(Player.COMMAND_GET_TRACKS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Pair<PlayerInfo, BundlingExclusions> mergeResult =
|
||||||
|
MediaUtils.mergePlayerInfo(
|
||||||
|
oldPlayerInfo,
|
||||||
|
BundlingExclusions.NONE,
|
||||||
|
newPlayerInfo,
|
||||||
|
new BundlingExclusions(/* isTimelineExcluded= */ true, /* areTracksExcluded= */ true),
|
||||||
|
availableCommands);
|
||||||
|
|
||||||
|
assertThat(mergeResult.first.timeline).isSameInstanceAs(oldPlayerInfo.timeline);
|
||||||
|
assertThat(mergeResult.first.currentTracks).isSameInstanceAs(oldPlayerInfo.currentTracks);
|
||||||
|
assertThat(mergeResult.second.isTimelineExcluded).isFalse();
|
||||||
|
assertThat(mergeResult.second.areCurrentTracksExcluded).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mergePlayerInfo_getTimelineCommandNotAvailable_emptyTimeline() {
|
||||||
|
Timeline timeline =
|
||||||
|
new Timeline.RemotableTimeline(
|
||||||
|
ImmutableList.of(new Timeline.Window()),
|
||||||
|
ImmutableList.of(new Timeline.Period()),
|
||||||
|
/* shuffledWindowIndices= */ new int[] {0});
|
||||||
|
Tracks tracks =
|
||||||
|
new Tracks(
|
||||||
|
ImmutableList.of(
|
||||||
|
new Tracks.Group(
|
||||||
|
new TrackGroup(new Format.Builder().setSampleMimeType(AUDIO_AAC).build()),
|
||||||
|
/* adaptiveSupported= */ false,
|
||||||
|
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
|
||||||
|
/* trackSelected= */ new boolean[] {true}),
|
||||||
|
new Tracks.Group(
|
||||||
|
new TrackGroup(
|
||||||
|
new Format.Builder().setSampleMimeType(VIDEO_H264).build(),
|
||||||
|
new Format.Builder().setSampleMimeType(VIDEO_H265).build()),
|
||||||
|
/* adaptiveSupported= */ true,
|
||||||
|
new int[] {C.FORMAT_HANDLED, C.FORMAT_UNSUPPORTED_TYPE},
|
||||||
|
/* trackSelected= */ new boolean[] {false, true})));
|
||||||
|
PlayerInfo oldPlayerInfo =
|
||||||
|
PlayerInfo.DEFAULT.copyWithCurrentTracks(tracks).copyWithTimeline(timeline);
|
||||||
|
PlayerInfo newPlayerInfo = PlayerInfo.DEFAULT;
|
||||||
|
Player.Commands availableCommands =
|
||||||
|
Player.Commands.EMPTY.buildUpon().add(Player.COMMAND_GET_TRACKS).build();
|
||||||
|
|
||||||
|
Pair<PlayerInfo, BundlingExclusions> mergeResult =
|
||||||
|
MediaUtils.mergePlayerInfo(
|
||||||
|
oldPlayerInfo,
|
||||||
|
BundlingExclusions.NONE,
|
||||||
|
newPlayerInfo,
|
||||||
|
new BundlingExclusions(/* isTimelineExcluded= */ true, /* areTracksExcluded= */ true),
|
||||||
|
availableCommands);
|
||||||
|
|
||||||
|
assertThat(mergeResult.first.timeline).isSameInstanceAs(Timeline.EMPTY);
|
||||||
|
assertThat(mergeResult.first.currentTracks).isSameInstanceAs(oldPlayerInfo.currentTracks);
|
||||||
|
assertThat(mergeResult.second.isTimelineExcluded).isTrue();
|
||||||
|
assertThat(mergeResult.second.areCurrentTracksExcluded).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mergePlayerInfo_getTracksCommandNotAvailable_emptyTracks() {
|
||||||
|
Timeline timeline =
|
||||||
|
new Timeline.RemotableTimeline(
|
||||||
|
ImmutableList.of(new Timeline.Window()),
|
||||||
|
ImmutableList.of(new Timeline.Period()),
|
||||||
|
/* shuffledWindowIndices= */ new int[] {0});
|
||||||
|
Tracks tracks =
|
||||||
|
new Tracks(
|
||||||
|
ImmutableList.of(
|
||||||
|
new Tracks.Group(
|
||||||
|
new TrackGroup(new Format.Builder().setSampleMimeType(AUDIO_AAC).build()),
|
||||||
|
/* adaptiveSupported= */ false,
|
||||||
|
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
|
||||||
|
/* trackSelected= */ new boolean[] {true}),
|
||||||
|
new Tracks.Group(
|
||||||
|
new TrackGroup(
|
||||||
|
new Format.Builder().setSampleMimeType(VIDEO_H264).build(),
|
||||||
|
new Format.Builder().setSampleMimeType(VIDEO_H265).build()),
|
||||||
|
/* adaptiveSupported= */ true,
|
||||||
|
new int[] {C.FORMAT_HANDLED, C.FORMAT_UNSUPPORTED_TYPE},
|
||||||
|
/* trackSelected= */ new boolean[] {false, true})));
|
||||||
|
PlayerInfo oldPlayerInfo =
|
||||||
|
PlayerInfo.DEFAULT.copyWithCurrentTracks(tracks).copyWithTimeline(timeline);
|
||||||
|
PlayerInfo newPlayerInfo = PlayerInfo.DEFAULT;
|
||||||
|
Player.Commands availableCommands =
|
||||||
|
Player.Commands.EMPTY.buildUpon().add(Player.COMMAND_GET_TIMELINE).build();
|
||||||
|
|
||||||
|
Pair<PlayerInfo, BundlingExclusions> mergeResult =
|
||||||
|
MediaUtils.mergePlayerInfo(
|
||||||
|
oldPlayerInfo,
|
||||||
|
BundlingExclusions.NONE,
|
||||||
|
newPlayerInfo,
|
||||||
|
new BundlingExclusions(/* isTimelineExcluded= */ true, /* areTracksExcluded= */ true),
|
||||||
|
availableCommands);
|
||||||
|
|
||||||
|
assertThat(mergeResult.first.timeline).isSameInstanceAs(oldPlayerInfo.timeline);
|
||||||
|
assertThat(mergeResult.first.currentTracks).isSameInstanceAs(Tracks.EMPTY);
|
||||||
|
assertThat(mergeResult.second.isTimelineExcluded).isFalse();
|
||||||
|
assertThat(mergeResult.second.areCurrentTracksExcluded).isTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user