From c7286472908aff8ecea818509cf9edf83c0ddd02 Mon Sep 17 00:00:00 2001 From: rohks Date: Tue, 17 May 2022 15:10:15 +0100 Subject: [PATCH] Create new class to store cues and timestamp. We need to pass timestamp for the list of cues so we are defining a new class CueGroup which will store both cues and timestamp. PiperOrigin-RevId: 449212054 --- RELEASENOTES.md | 2 + .../java/androidx/media3/cast/CastPlayer.java | 8 +- .../media3/common/ForwardingPlayer.java | 8 +- .../java/androidx/media3/common/Player.java | 24 +++- .../androidx/media3/common/text/CueGroup.java | 103 ++++++++++++++++++ .../media3/common/text/CueGroupTest.java | 55 ++++++++++ .../androidx/media3/exoplayer/ExoPlayer.java | 4 +- .../media3/exoplayer/ExoPlayerImpl.java | 21 ++-- .../media3/exoplayer/SimpleExoPlayer.java | 4 +- .../analytics/AnalyticsListener.java | 21 +++- .../analytics/DefaultAnalyticsCollector.java | 9 ++ .../media3/exoplayer/text/TextOutput.java | 16 ++- .../media3/exoplayer/text/TextRenderer.java | 2 + .../media3/session/MediaController.java | 9 +- .../session/MediaControllerImplBase.java | 13 ++- .../session/MediaControllerImplLegacy.java | 8 +- .../media3/session/MediaSessionImpl.java | 6 +- .../androidx/media3/session/MediaUtils.java | 16 --- .../androidx/media3/session/PlayerInfo.java | 40 +++---- .../media3/session/PlayerWrapper.java | 4 +- .../session/common/IRemoteMediaSession.aidl | 2 +- .../test/session/common/CommonConstants.java | 2 +- .../session/MediaControllerListenerTest.java | 23 ++-- .../media3/session/MediaUtilsTest.java | 15 --- .../session/MediaSessionProviderService.java | 18 ++- .../androidx/media3/session/MockPlayer.java | 14 ++- .../media3/session/RemoteMediaSession.java | 12 +- .../media3/test/utils/StubPlayer.java | 4 +- .../java/androidx/media3/ui/PlayerView.java | 2 +- 29 files changed, 329 insertions(+), 136 deletions(-) create mode 100644 libraries/common/src/main/java/androidx/media3/common/text/CueGroup.java create mode 100644 libraries/common/src/test/java/androidx/media3/common/text/CueGroupTest.java diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7e62826e08..883e3271ad 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -28,6 +28,8 @@ * Decrease ad polling rate from every 100ms to every 200ms, to line up with Media Rating Council (MRC) recommendations. * Text: + * Change `Player.getCurrentCues()` to return `CueGroup` instead of + `List`. * SSA: Support `OutlineColour` style setting when `BorderStyle == 3` (i.e. `OutlineColour` sets the background of the cue) ([#8435](https://github.com/google/ExoPlayer/issues/8435)). diff --git a/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java b/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java index 488af70f50..3ab3878864 100644 --- a/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java +++ b/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java @@ -42,7 +42,7 @@ import androidx.media3.common.TrackGroup; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Clock; import androidx.media3.common.util.ListenerSet; @@ -705,10 +705,10 @@ public final class CastPlayer extends BasePlayer { return VideoSize.UNKNOWN; } - /** This method is not supported and returns an empty list. */ + /** This method is not supported and returns an empty {@link CueGroup}. */ @Override - public ImmutableList getCurrentCues() { - return ImmutableList.of(); + public CueGroup getCurrentCues() { + return CueGroup.EMPTY; } /** This method is not supported and always returns {@link DeviceInfo#UNKNOWN}. */ diff --git a/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java b/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java index 63ec6b1a72..b6fb7111df 100644 --- a/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java +++ b/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java @@ -22,6 +22,7 @@ import android.view.SurfaceView; import android.view.TextureView; import androidx.annotation.Nullable; import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.UnstableApi; import java.util.List; @@ -752,7 +753,7 @@ public class ForwardingPlayer implements Player { /** Calls {@link Player#getCurrentCues()} on the delegate and returns the result. */ @Override - public List getCurrentCues() { + public CueGroup getCurrentCues() { return player.getCurrentCues(); } @@ -992,6 +993,11 @@ public class ForwardingPlayer implements Player { listener.onCues(cues); } + @Override + public void onCues(CueGroup cueGroup) { + listener.onCues(cueGroup); + } + @Override public void onMetadata(Metadata metadata) { listener.onMetadata(metadata); diff --git a/libraries/common/src/main/java/androidx/media3/common/Player.java b/libraries/common/src/main/java/androidx/media3/common/Player.java index acaf8ded95..eb67acb05e 100644 --- a/libraries/common/src/main/java/androidx/media3/common/Player.java +++ b/libraries/common/src/main/java/androidx/media3/common/Player.java @@ -32,6 +32,7 @@ import androidx.annotation.IntDef; import androidx.annotation.IntRange; import androidx.annotation.Nullable; import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.BundleableUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -1024,16 +1025,29 @@ public interface Player { /** * Called when there is a change in the {@link Cue Cues}. * - *

{@code cues} is in ascending order of priority. If any of the cue boxes overlap when - * displayed, the {@link Cue} nearer the end of the list should be shown on top. + *

Both {@link #onCues(List)} and {@link #onCues(CueGroup)} are called when there is a change + * in the cues. You should only implement one or the other. * *

{@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. * - * @param cues The {@link Cue Cues}. May be empty. + * @deprecated Use {@link #onCues(CueGroup)} instead. */ + @Deprecated + @UnstableApi default void onCues(List cues) {} + /** + * Called when there is a change in the {@link CueGroup}. + * + *

Both {@link #onCues(List)} and {@link #onCues(CueGroup)} are called when there is a change + * in the cues. You should only implement one or the other. + * + *

{@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. + */ + default void onCues(CueGroup cueGroup) {} + /** * Called when there is metadata associated with the current playback time. * @@ -2469,8 +2483,8 @@ public interface Player { */ VideoSize getVideoSize(); - /** Returns the current {@link Cue Cues}. This list may be empty. */ - List getCurrentCues(); + /** Returns the current {@link CueGroup}. */ + CueGroup getCurrentCues(); /** Gets the device information. */ DeviceInfo getDeviceInfo(); diff --git a/libraries/common/src/main/java/androidx/media3/common/text/CueGroup.java b/libraries/common/src/main/java/androidx/media3/common/text/CueGroup.java new file mode 100644 index 0000000000..b982b52274 --- /dev/null +++ b/libraries/common/src/main/java/androidx/media3/common/text/CueGroup.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2022 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.common.text; + +import static java.lang.annotation.ElementType.TYPE_USE; + +import android.graphics.Bitmap; +import android.os.Bundle; +import androidx.annotation.IntDef; +import androidx.media3.common.Bundleable; +import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.UnstableApi; +import com.google.common.collect.ImmutableList; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; + +/** Class to represent the state of active {@link Cue Cues} at a particular time. */ +public final class CueGroup implements Bundleable { + + /** Empty {@link CueGroup}. */ + @UnstableApi public static final CueGroup EMPTY = new CueGroup(ImmutableList.of()); + + /** + * The cues in this group. + * + *

This list is in ascending order of priority. If any of the cue boxes overlap when displayed, + * the {@link Cue} nearer the end of the list should be shown on top. + * + *

This list may be empty if the group represents a state with no cues. + */ + public final ImmutableList cues; + + /** Creates a CueGroup. */ + @UnstableApi + public CueGroup(List cues) { + this.cues = ImmutableList.copyOf(cues); + } + + // Bundleable implementation. + + @Documented + @Retention(RetentionPolicy.SOURCE) + @Target(TYPE_USE) + @IntDef({FIELD_CUES}) + private @interface FieldNumber {} + + private static final int FIELD_CUES = 0; + + @UnstableApi + @Override + public Bundle toBundle() { + Bundle bundle = new Bundle(); + bundle.putParcelableArrayList( + keyForField(FIELD_CUES), BundleableUtil.toBundleArrayList(filterOutBitmapCues(cues))); + return bundle; + } + + @UnstableApi public static final Creator CREATOR = CueGroup::fromBundle; + + private static final CueGroup fromBundle(Bundle bundle) { + List cues = + BundleableUtil.fromBundleNullableList( + Cue.CREATOR, + bundle.getParcelableArrayList(keyForField(FIELD_CUES)), + /* defaultValue= */ ImmutableList.of()); + return new CueGroup(cues); + } + + private static String keyForField(@FieldNumber int field) { + return Integer.toString(field, Character.MAX_RADIX); + } + + /** + * Filters out {@link Cue} objects containing {@link Bitmap}. It is used when transferring cues + * between processes to prevent transferring too much data. + */ + private static ImmutableList filterOutBitmapCues(List cues) { + ImmutableList.Builder builder = ImmutableList.builder(); + for (int i = 0; i < cues.size(); i++) { + if (cues.get(i).bitmap != null) { + continue; + } + builder.add(cues.get(i)); + } + return builder.build(); + } +} diff --git a/libraries/common/src/test/java/androidx/media3/common/text/CueGroupTest.java b/libraries/common/src/test/java/androidx/media3/common/text/CueGroupTest.java new file mode 100644 index 0000000000..6a8f4d6e9c --- /dev/null +++ b/libraries/common/src/test/java/androidx/media3/common/text/CueGroupTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 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.common.text; + +import static com.google.common.truth.Truth.assertThat; + +import android.graphics.Bitmap; +import android.os.Bundle; +import android.os.Parcel; +import android.text.SpannedString; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.common.collect.ImmutableList; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for {@link CueGroup}. */ +@RunWith(AndroidJUnit4.class) +public class CueGroupTest { + + @Test + public void bundleAndUnBundleCueGroup() { + Cue textCue = new Cue.Builder().setText(SpannedString.valueOf("text")).build(); + Cue bitmapCue = + new Cue.Builder().setBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)).build(); + ImmutableList cues = ImmutableList.of(textCue, bitmapCue); + CueGroup cueGroup = new CueGroup(cues); + + Parcel parcel = Parcel.obtain(); + try { + parcel.writeBundle(cueGroup.toBundle()); + parcel.setDataPosition(0); + + Bundle bundle = parcel.readBundle(); + CueGroup filteredCueGroup = CueGroup.CREATOR.fromBundle(bundle); + + assertThat(filteredCueGroup.cues).containsExactly(textCue); + } finally { + parcel.recycle(); + } + } +} diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayer.java index 4dc3f66026..1efe41836c 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayer.java @@ -40,7 +40,7 @@ import androidx.media3.common.PriorityTaskManager; import androidx.media3.common.Timeline; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Clock; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -358,7 +358,7 @@ public interface ExoPlayer extends Player { * @deprecated Use {@link Player#getCurrentCues()} instead. */ @Deprecated - List getCurrentCues(); + CueGroup getCurrentCues(); } /** diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java index abc8db3654..8902e5d76f 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java @@ -73,6 +73,7 @@ import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Clock; import androidx.media3.common.util.ConditionVariable; @@ -196,7 +197,7 @@ import java.util.concurrent.TimeoutException; private AudioAttributes audioAttributes; private float volume; private boolean skipSilenceEnabled; - private List currentCues; + private CueGroup currentCueGroup; @Nullable private VideoFrameMetadataListener videoFrameMetadataListener; @Nullable private CameraMotionListener cameraMotionListener; private boolean throwsWhenUsingWrongThread; @@ -353,7 +354,7 @@ import java.util.concurrent.TimeoutException; } else { audioSessionId = Util.generateAudioSessionIdV21(applicationContext); } - currentCues = ImmutableList.of(); + currentCueGroup = CueGroup.EMPTY; throwsWhenUsingWrongThread = true; addListener(analyticsCollector); @@ -936,7 +937,7 @@ import java.util.concurrent.TimeoutException; verifyApplicationThread(); audioFocusManager.updateAudioFocus(getPlayWhenReady(), Player.STATE_IDLE); stopInternal(reset, /* error= */ null); - currentCues = ImmutableList.of(); + currentCueGroup = CueGroup.EMPTY; } @Override @@ -990,7 +991,7 @@ import java.util.concurrent.TimeoutException; checkNotNull(priorityTaskManager).remove(C.PRIORITY_PLAYBACK); isPriorityTaskManagerRegistered = false; } - currentCues = ImmutableList.of(); + currentCueGroup = CueGroup.EMPTY; playerReleased = true; } @@ -1587,9 +1588,9 @@ import java.util.concurrent.TimeoutException; } @Override - public List getCurrentCues() { + public CueGroup getCurrentCues() { verifyApplicationThread(); - return currentCues; + return currentCueGroup; } @Override @@ -2850,13 +2851,17 @@ import java.util.concurrent.TimeoutException; } // TextOutput implementation - @Override public void onCues(List cues) { - currentCues = cues; listeners.sendEvent(EVENT_CUES, listener -> listener.onCues(cues)); } + @Override + public void onCues(CueGroup cueGroup) { + currentCueGroup = cueGroup; + listeners.sendEvent(EVENT_CUES, listener -> listener.onCues(cueGroup)); + } + // MetadataOutput implementation @Override diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/SimpleExoPlayer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/SimpleExoPlayer.java index fc6e8889d2..3d4a315ab3 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/SimpleExoPlayer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/SimpleExoPlayer.java @@ -38,7 +38,7 @@ import androidx.media3.common.Timeline; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Clock; import androidx.media3.common.util.ConditionVariable; import androidx.media3.common.util.UnstableApi; @@ -690,7 +690,7 @@ public class SimpleExoPlayer extends BasePlayer } @Override - public List getCurrentCues() { + public CueGroup getCurrentCues() { blockUntilConstructorFinished(); return player.getCurrentCues(); } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/AnalyticsListener.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/AnalyticsListener.java index 2c9345409f..454588936a 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/AnalyticsListener.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/AnalyticsListener.java @@ -49,6 +49,7 @@ import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.UnstableApi; import androidx.media3.decoder.DecoderException; import androidx.media3.exoplayer.DecoderCounters; @@ -875,15 +876,29 @@ public interface AnalyticsListener { /** * Called when there is a change in the {@link Cue Cues}. * - *

{@code cues} is in ascending order of priority. If any of the cue boxes overlap when - * displayed, the {@link Cue} nearer the end of the list should be shown on top. + *

Both {@link #onCues(EventTime, List)} and {@link #onCues(EventTime, CueGroup)} are called + * when there is a change in the cues. You should only implement one or the other. * * @param eventTime The event time. - * @param cues The {@link Cue Cues}. May be empty. + * @param cues The {@link Cue Cues}. + * @deprecated Use {@link #onCues(EventTime, CueGroup)} instead. */ + @Deprecated @UnstableApi default void onCues(EventTime eventTime, List cues) {} + /** + * Called when there is a change in the {@link CueGroup}. + * + *

Both {@link #onCues(EventTime, List)} and {@link #onCues(EventTime, CueGroup)} are called + * when there is a change in the cues. You should only implement one or the other. + * + * @param eventTime The event time. + * @param cueGroup The {@link CueGroup}. + */ + @UnstableApi + default void onCues(EventTime eventTime, CueGroup cueGroup) {} + /** * @deprecated Use {@link #onAudioEnabled} and {@link #onVideoEnabled} instead. */ diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/DefaultAnalyticsCollector.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/DefaultAnalyticsCollector.java index 8ae6985a6d..74062ab3e3 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/DefaultAnalyticsCollector.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/analytics/DefaultAnalyticsCollector.java @@ -42,6 +42,7 @@ import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Clock; import androidx.media3.common.util.HandlerWrapper; import androidx.media3.common.util.ListenerSet; @@ -695,6 +696,7 @@ public class DefaultAnalyticsCollector implements AnalyticsCollector { listener -> listener.onMetadata(eventTime, metadata)); } + @SuppressWarnings("deprecation") // Implementing and calling deprecated listener method. @Override public void onCues(List cues) { EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime(); @@ -702,6 +704,13 @@ public class DefaultAnalyticsCollector implements AnalyticsCollector { eventTime, AnalyticsListener.EVENT_CUES, listener -> listener.onCues(eventTime, cues)); } + @Override + public void onCues(CueGroup cueGroup) { + EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime(); + sendEvent( + eventTime, AnalyticsListener.EVENT_CUES, listener -> listener.onCues(eventTime, cueGroup)); + } + @SuppressWarnings("deprecation") // Implementing and calling deprecated listener method. @Override public final void onSeekProcessed() { diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextOutput.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextOutput.java index 73983208b7..2201d519bf 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextOutput.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextOutput.java @@ -16,6 +16,7 @@ package androidx.media3.exoplayer.text; import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.UnstableApi; import java.util.List; @@ -26,10 +27,19 @@ public interface TextOutput { /** * Called when there is a change in the {@link Cue Cues}. * - *

{@code cues} is in ascending order of priority. If any of the cue boxes overlap when - * displayed, the {@link Cue} nearer the end of the list should be shown on top. + *

Both {@link #onCues(List)} and {@link #onCues(CueGroup)} are called when there is a change + * in the cues. You should only implement one or the other. * - * @param cues The {@link Cue Cues}. May be empty. + * @deprecated Use {@link #onCues(CueGroup)} instead. */ + @Deprecated void onCues(List cues); + + /** + * Called when there is a change in the {@link CueGroup}. + * + *

Both {@link #onCues(List)} and {@link #onCues(CueGroup)} are called when there is a change + * in the cues You should only implement one or the other. + */ + default void onCues(CueGroup cueGroup) {} } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java index af8809966a..506a69a842 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java @@ -29,6 +29,7 @@ import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Log; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -395,6 +396,7 @@ public final class TextRenderer extends BaseRenderer implements Callback { private void invokeUpdateOutputInternal(List cues) { output.onCues(cues); + output.onCues(new CueGroup(cues)); } /** diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaController.java b/libraries/session/src/main/java/androidx/media3/session/MediaController.java index d1c4bf65f7..9a45735e39 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaController.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaController.java @@ -52,12 +52,11 @@ import androidx.media3.common.Timeline; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Consumer; import androidx.media3.common.util.Log; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; -import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.List; @@ -1583,9 +1582,9 @@ public class MediaController implements Player { } @Override - public List getCurrentCues() { + public CueGroup getCurrentCues() { verifyApplicationThread(); - return isConnected() ? impl.getCurrentCues() : ImmutableList.of(); + return isConnected() ? impl.getCurrentCues() : CueGroup.EMPTY; } @Override @@ -1981,7 +1980,7 @@ public class MediaController implements Player { void clearVideoTextureView(@Nullable TextureView textureView); - List getCurrentCues(); + CueGroup getCurrentCues(); float getVolume(); diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java index b2420b835a..a0c55ff9a8 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java @@ -134,7 +134,7 @@ import androidx.media3.common.Timeline.RemotableTimeline; import androidx.media3.common.Timeline.Window; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.BundleableUtil; import androidx.media3.common.util.Clock; import androidx.media3.common.util.ListenerSet; @@ -1490,8 +1490,8 @@ import org.checkerframework.checker.nullness.qual.NonNull; } @Override - public List getCurrentCues() { - return playerInfo.cues; + public CueGroup getCurrentCues() { + return playerInfo.cueGroup; } @Override @@ -2356,6 +2356,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; }); } + @SuppressWarnings("deprecation") // Implementing and calling deprecated listener method. void onPlayerInfoChanged( PlayerInfo newPlayerInfo, @TimelineChangeReason int timelineChangedReason, @@ -2427,10 +2428,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; /* eventFlag= */ C.INDEX_UNSET, listener -> listener.onAudioAttributesChanged(playerInfo.audioAttributes)); } - if (!Util.areEqual(oldPlayerInfo.cues, playerInfo.cues)) { + if (!oldPlayerInfo.cueGroup.cues.equals(playerInfo.cueGroup.cues)) { // TODO(b/187152483): Set proper event code when available. listeners.queueEvent( - /* eventFlag= */ C.INDEX_UNSET, listener -> listener.onCues(playerInfo.cues)); + /* eventFlag= */ C.INDEX_UNSET, listener -> listener.onCues(playerInfo.cueGroup.cues)); + listeners.queueEvent( + /* eventFlag= */ C.INDEX_UNSET, listener -> listener.onCues(playerInfo.cueGroup)); } if (!Util.areEqual(oldPlayerInfo.deviceInfo, playerInfo.deviceInfo)) { // TODO(b/187152483): Set proper event code when available. diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java index 4de254cd50..ae8d72d10a 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java @@ -91,7 +91,7 @@ import androidx.media3.common.Timeline; import androidx.media3.common.Timeline.Window; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Clock; import androidx.media3.common.util.ListenerSet; import androidx.media3.common.util.Log; @@ -1052,9 +1052,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; } @Override - public List getCurrentCues() { + public CueGroup getCurrentCues() { Log.w(TAG, "Session doesn't support getting Cue"); - return ImmutableList.of(); + return CueGroup.EMPTY; } @Override @@ -2042,7 +2042,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; /* playlistMetadata= */ playlistMetadata, /* volume= */ 1.0f, /* audioAttributes= */ audioAttributes, - /* cues= */ Collections.emptyList(), + /* cueGroup= */ CueGroup.EMPTY, /* deviceInfo= */ deviceInfo, /* deviceVolume= */ deviceVolume, /* deviceMuted= */ deviceMuted, diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java index f7f83018d6..23aea7e72f 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java @@ -62,7 +62,7 @@ import androidx.media3.common.Rating; import androidx.media3.common.Timeline; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Log; import androidx.media3.common.util.Util; import androidx.media3.session.MediaSession.ControllerCb; @@ -1016,7 +1016,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; } @Override - public void onCues(List cues) { + public void onCues(CueGroup cueGroup) { @Nullable MediaSessionImpl session = getSession(); if (session == null) { return; @@ -1026,7 +1026,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; if (player == null) { return; } - session.playerInfo = new PlayerInfo.Builder(session.playerInfo).setCues(cues).build(); + session.playerInfo = new PlayerInfo.Builder(session.playerInfo).setCues(cueGroup).build(); session.onPlayerInfoChangedHandler.sendPlayerInfoChangedMessage(/* excludeTimeline= */ true); } diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java b/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java index 36c0325099..16e984daeb 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java @@ -81,7 +81,6 @@ import androidx.media3.common.ThumbRating; import androidx.media3.common.Timeline; import androidx.media3.common.Timeline.Period; import androidx.media3.common.Timeline.Window; -import androidx.media3.common.text.Cue; import androidx.media3.common.util.Log; import androidx.media3.common.util.Util; import androidx.media3.session.MediaLibraryService.LibraryParams; @@ -1267,21 +1266,6 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; return intersectCommandsBuilder.build(); } - /** - * Filters out {@link Cue} objects containing {@link Bitmap}. It is used when transferring cues - * between processes to prevent transferring too large data. - */ - public static ImmutableList filterOutBitmapCues(List cues) { - ImmutableList.Builder builder = ImmutableList.builder(); - for (int i = 0; i < cues.size(); i++) { - if (cues.get(i).bitmap != null) { - continue; - } - builder.add(cues.get(i)); - } - return builder.build(); - } - private static byte[] convertToByteArray(Bitmap bitmap) throws IOException { try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { bitmap.compress(Bitmap.CompressFormat.PNG, /* ignored */ 0, stream); diff --git a/libraries/session/src/main/java/androidx/media3/session/PlayerInfo.java b/libraries/session/src/main/java/androidx/media3/session/PlayerInfo.java index ea9b7166fe..87e3637fc4 100644 --- a/libraries/session/src/main/java/androidx/media3/session/PlayerInfo.java +++ b/libraries/session/src/main/java/androidx/media3/session/PlayerInfo.java @@ -43,15 +43,13 @@ import androidx.media3.common.Timeline; import androidx.media3.common.Timeline.Window; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.BundleableUtil; -import com.google.common.collect.ImmutableList; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.List; /** * Information about the player that {@link MediaSession} uses to send its state to {@link @@ -75,7 +73,7 @@ import java.util.List; private MediaMetadata playlistMetadata; private float volume; private AudioAttributes audioAttributes; - private ImmutableList cues; + private CueGroup cueGroup; private DeviceInfo deviceInfo; private int deviceVolume; private boolean deviceMuted; @@ -106,7 +104,7 @@ import java.util.List; playlistMetadata = playerInfo.playlistMetadata; volume = playerInfo.volume; audioAttributes = playerInfo.audioAttributes; - cues = ImmutableList.copyOf(playerInfo.cues); + cueGroup = playerInfo.cueGroup; deviceInfo = playerInfo.deviceInfo; deviceVolume = playerInfo.deviceVolume; deviceMuted = playerInfo.deviceMuted; @@ -194,8 +192,8 @@ import java.util.List; return this; } - public Builder setCues(List cues) { - this.cues = ImmutableList.copyOf(cues); + public Builder setCues(CueGroup cueGroup) { + this.cueGroup = cueGroup; return this; } @@ -290,7 +288,7 @@ import java.util.List; playlistMetadata, volume, audioAttributes, - cues, + cueGroup, deviceInfo, deviceVolume, deviceMuted, @@ -335,7 +333,7 @@ import java.util.List; MediaMetadata.EMPTY, /* volume= */ 1f, AudioAttributes.DEFAULT, - /* cues = */ ImmutableList.of(), + /* cueGroup = */ CueGroup.EMPTY, DeviceInfo.UNKNOWN, /* deviceVolume= */ 0, /* deviceMuted= */ false, @@ -379,7 +377,7 @@ import java.util.List; public final AudioAttributes audioAttributes; - public final List cues; + public final CueGroup cueGroup; public final DeviceInfo deviceInfo; @@ -597,7 +595,7 @@ import java.util.List; MediaMetadata playlistMetadata, float volume, AudioAttributes audioAttributes, - List cues, + CueGroup cueGroup, DeviceInfo deviceInfo, int deviceVolume, boolean deviceMuted, @@ -626,7 +624,7 @@ import java.util.List; this.playlistMetadata = playlistMetadata; this.volume = volume; this.audioAttributes = audioAttributes; - this.cues = cues; + this.cueGroup = cueGroup; this.deviceInfo = deviceInfo; this.deviceVolume = deviceVolume; this.deviceMuted = deviceMuted; @@ -689,7 +687,7 @@ import java.util.List; FIELD_OLD_POSITION_INFO, FIELD_NEW_POSITION_INFO, FIELD_DISCONTINUITY_REASON, - FIELD_CUES, + FIELD_CUE_GROUP, FIELD_MEDIA_METADATA, FIELD_SEEK_BACK_INCREMENT_MS, FIELD_SEEK_FORWARD_INCREMENT_MS, @@ -721,7 +719,7 @@ import java.util.List; private static final int FIELD_OLD_POSITION_INFO = 21; private static final int FIELD_NEW_POSITION_INFO = 22; private static final int FIELD_DISCONTINUITY_REASON = 23; - private static final int FIELD_CUES = 24; + private static final int FIELD_CUE_GROUP = 24; private static final int FIELD_MEDIA_METADATA = 25; private static final int FIELD_SEEK_BACK_INCREMENT_MS = 26; private static final int FIELD_SEEK_FORWARD_INCREMENT_MS = 27; @@ -759,9 +757,7 @@ import java.util.List; bundle.putFloat(keyForField(FIELD_VOLUME), volume); bundle.putBundle(keyForField(FIELD_AUDIO_ATTRIBUTES), audioAttributes.toBundle()); if (!excludeCues) { - bundle.putParcelableArrayList( - keyForField(FIELD_CUES), - BundleableUtil.toBundleArrayList(MediaUtils.filterOutBitmapCues(cues))); + bundle.putBundle(keyForField(FIELD_CUE_GROUP), cueGroup.toBundle()); } bundle.putBundle(keyForField(FIELD_DEVICE_INFO), deviceInfo.toBundle()); bundle.putInt(keyForField(FIELD_DEVICE_VOLUME), deviceVolume); @@ -851,11 +847,9 @@ import java.util.List; AudioAttributes.CREATOR, bundle.getBundle(keyForField(FIELD_AUDIO_ATTRIBUTES)), /* defaultValue= */ AudioAttributes.DEFAULT); - List cues = - BundleableUtil.fromBundleNullableList( - Cue.CREATOR, - bundle.getParcelableArrayList(keyForField(FIELD_CUES)), - /* defaultValue= */ ImmutableList.of()); + CueGroup cueGroup = + BundleableUtil.fromNullableBundle( + CueGroup.CREATOR, bundle.getBundle(keyForField(FIELD_CUE_GROUP)), CueGroup.EMPTY); @Nullable Bundle deviceInfoBundle = bundle.getBundle(keyForField(FIELD_DEVICE_INFO)); DeviceInfo deviceInfo = BundleableUtil.fromNullableBundle( @@ -912,7 +906,7 @@ import java.util.List; playlistMetadata, volume, audioAttributes, - cues, + cueGroup, deviceInfo, deviceVolume, deviceMuted, diff --git a/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java b/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java index 41716c5edd..d1f25b41cd 100644 --- a/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java +++ b/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java @@ -42,7 +42,7 @@ import androidx.media3.common.Player; import androidx.media3.common.Timeline; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.Log; import androidx.media3.common.util.Util; import com.google.common.collect.ImmutableList; @@ -636,7 +636,7 @@ import java.util.List; } @Override - public List getCurrentCues() { + public CueGroup getCurrentCues() { verifyApplicationThread(); return super.getCurrentCues(); } diff --git a/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaSession.aidl b/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaSession.aidl index 34cadaa574..30972501fa 100644 --- a/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaSession.aidl +++ b/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaSession.aidl @@ -77,7 +77,7 @@ interface IRemoteMediaSession { void notifySeekBackIncrementChanged(String sessionId, long seekBackIncrementMs); void notifySeekForwardIncrementChanged(String sessionId, long seekForwardIncrementMs); void notifyDeviceVolumeChanged(String sessionId, int volume, boolean muted); - void notifyCuesChanged(String sessionId, in List cues); + void notifyCuesChanged(String sessionId, in Bundle cueGroup); void notifyDeviceInfoChanged(String sessionId, in Bundle deviceInfo); void notifyMediaMetadataChanged(String sessionId, in Bundle mediaMetadata); void notifyRenderedFirstFrame(String sessionId); diff --git a/libraries/test_session_common/src/main/java/androidx/media3/test/session/common/CommonConstants.java b/libraries/test_session_common/src/main/java/androidx/media3/test/session/common/CommonConstants.java index 251ad12de8..3260732471 100644 --- a/libraries/test_session_common/src/main/java/androidx/media3/test/session/common/CommonConstants.java +++ b/libraries/test_session_common/src/main/java/androidx/media3/test/session/common/CommonConstants.java @@ -99,7 +99,7 @@ public class CommonConstants { public static final String KEY_IS_PLAYING_AD = "isPlayingAd"; public static final String KEY_CURRENT_AD_GROUP_INDEX = "currentAdGroupIndex"; public static final String KEY_CURRENT_AD_INDEX_IN_AD_GROUP = "currentAdIndexInAdGroup"; - public static final String KEY_CURRENT_CUES = "currentCues"; + public static final String KEY_CURRENT_CUE_GROUP = "currentCueGroup"; public static final String KEY_MEDIA_METADATA = "mediaMetadata"; public static final String KEY_MAX_SEEK_TO_PREVIOUS_POSITION_MS = "maxSeekToPreviousPositionMs"; public static final String KEY_TRACK_SELECTION_PARAMETERS = "trackSelectionParameters"; diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java index e67a984cbe..2ca7d1dc14 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java @@ -63,6 +63,7 @@ import androidx.media3.common.Timeline; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.VideoSize; import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.session.RemoteMediaSession.RemoteMockPlayer; import androidx.media3.test.session.common.HandlerThreadTestRule; import androidx.media3.test.session.common.MainLooperTestRule; @@ -1842,12 +1843,14 @@ public class MediaControllerListenerTest { List testCues = ImmutableList.of(testCue1, testCue2); Bundle playerConfig = - new RemoteMediaSession.MockPlayerConfigBuilder().setCurrentCues(testCues).build(); + new RemoteMediaSession.MockPlayerConfigBuilder() + .setCurrentCues(new CueGroup(testCues)) + .build(); remoteSession.setPlayer(playerConfig); MediaController controller = controllerTestRule.createController(remoteSession.getToken()); - assertThat(threadTestRule.getHandler().postAndSync(controller::getCurrentCues)) + assertThat(threadTestRule.getHandler().postAndSync(controller::getCurrentCues).cues) .isEqualTo(testCues); } @@ -1858,7 +1861,9 @@ public class MediaControllerListenerTest { List testCues = ImmutableList.of(testCue1, testCue2); Bundle playerConfig = - new RemoteMediaSession.MockPlayerConfigBuilder().setCurrentCues(testCues).build(); + new RemoteMediaSession.MockPlayerConfigBuilder() + .setCurrentCues(new CueGroup(testCues)) + .build(); remoteSession.setPlayer(playerConfig); MediaController controller = controllerTestRule.createController(remoteSession.getToken()); @@ -1873,7 +1878,7 @@ public class MediaControllerListenerTest { cuesFromParam.clear(); cuesFromParam.addAll(cues); cuesFromGetter.clear(); - cuesFromGetter.addAll(controller.getCurrentCues()); + cuesFromGetter.addAll(controller.getCurrentCues().cues); latch.countDown(); } }; @@ -1902,14 +1907,16 @@ public class MediaControllerListenerTest { @Override public void onCues(List cues) { cuesFromParam.addAll(cues); - cuesFromGetter.addAll(controller.getCurrentCues()); + cuesFromGetter.addAll(controller.getCurrentCues().cues); latch.countDown(); } }; controller.addListener(listener); Bundle playerConfig = - new RemoteMediaSession.MockPlayerConfigBuilder().setCurrentCues(testCues).build(); + new RemoteMediaSession.MockPlayerConfigBuilder() + .setCurrentCues(new CueGroup(testCues)) + .build(); remoteSession.setPlayer(playerConfig); assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); @@ -1932,13 +1939,13 @@ public class MediaControllerListenerTest { @Override public void onCues(List cues) { cuesFromParam.addAll(cues); - cuesFromGetter.addAll(controller.getCurrentCues()); + cuesFromGetter.addAll(controller.getCurrentCues().cues); latch.countDown(); } }; threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener)); - remoteSession.getMockPlayer().notifyCuesChanged(testCues); + remoteSession.getMockPlayer().notifyCuesChanged(new CueGroup(testCues)); assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); assertThat(cuesFromParam).isEqualTo(testCues); diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaUtilsTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaUtilsTest.java index 5e113440b6..cbde70120c 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaUtilsTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaUtilsTest.java @@ -20,7 +20,6 @@ import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_Q import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import android.graphics.Bitmap; import android.os.Bundle; import android.os.Parcel; import android.service.media.MediaBrowserService; @@ -31,7 +30,6 @@ import android.support.v4.media.RatingCompat; import android.support.v4.media.session.MediaControllerCompat; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; -import android.text.SpannedString; import android.text.TextUtils; import androidx.media.AudioAttributesCompat; import androidx.media3.common.AudioAttributes; @@ -44,12 +42,10 @@ import androidx.media3.common.Player; import androidx.media3.common.Rating; import androidx.media3.common.StarRating; import androidx.media3.common.ThumbRating; -import androidx.media3.common.text.Cue; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SdkSuppress; import androidx.test.filters.SmallTest; -import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -424,17 +420,6 @@ public final class MediaUtilsTest { assertThat(MediaUtils.convertToAudioAttributesCompat(aa)).isEqualTo(aaCompat); } - @Test - public void filterOutBitmapCues_dropsBitmap() { - Cue textCue = new Cue.Builder().setText(SpannedString.valueOf("text")).build(); - Cue bitmapCue = - new Cue.Builder().setBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)).build(); - List filteredCues = MediaUtils.filterOutBitmapCues(ImmutableList.of(textCue, bitmapCue)); - - assertThat(filteredCues).hasSize(1); - assertThat(filteredCues.get(0)).isEqualTo(textCue); - } - @Test public void convertToCurrentPosition_byDefault_returnsZero() { long currentPositionMs = diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java index c005fd5cd2..9d6eafcf83 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java @@ -24,7 +24,7 @@ import static androidx.media3.test.session.common.CommonConstants.KEY_CONTENT_DU import static androidx.media3.test.session.common.CommonConstants.KEY_CONTENT_POSITION; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_AD_GROUP_INDEX; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_AD_INDEX_IN_AD_GROUP; -import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_CUES; +import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_CUE_GROUP; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_LIVE_OFFSET; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_MEDIA_ITEM_INDEX; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_PERIOD_INDEX; @@ -78,7 +78,7 @@ import androidx.media3.common.Player.PositionInfo; import androidx.media3.common.Timeline; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.BundleableUtil; import androidx.media3.common.util.Log; import androidx.media3.common.util.UnstableApi; @@ -306,10 +306,9 @@ public class MediaSessionProviderService extends Service { AudioAttributes.CREATOR, config.getBundle(KEY_AUDIO_ATTRIBUTES), player.audioAttributes); - @Nullable List cuesBundleList = config.getParcelableArrayList(KEY_CURRENT_CUES); - if (cuesBundleList != null) { - player.cues = BundleableUtil.fromBundleList(Cue.CREATOR, cuesBundleList); - } + player.cueGroup = + BundleableUtil.fromNullableBundle( + CueGroup.CREATOR, config.getBundle(KEY_CURRENT_CUE_GROUP), CueGroup.EMPTY); player.deviceInfo = BundleableUtil.fromNullableBundle( DeviceInfo.CREATOR, config.getBundle(KEY_DEVICE_INFO), player.deviceInfo); @@ -886,14 +885,13 @@ public class MediaSessionProviderService extends Service { } @Override - public void notifyCuesChanged(String sessionId, List cueBundleList) - throws RemoteException { - List cues = BundleableUtil.fromBundleList(Cue.CREATOR, cueBundleList); + public void notifyCuesChanged(String sessionId, Bundle cueGroupBundle) throws RemoteException { + CueGroup cueGroup = CueGroup.CREATOR.fromBundle(cueGroupBundle); runOnHandler( () -> { MediaSession session = sessionMap.get(sessionId); MockPlayer player = (MockPlayer) session.getPlayer(); - player.cues = cues; + player.cueGroup = cueGroup; player.notifyCuesChanged(); }); } diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/MockPlayer.java b/libraries/test_session_current/src/main/java/androidx/media3/session/MockPlayer.java index e3635e7e2b..5cc4bd8cc1 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/MockPlayer.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/MockPlayer.java @@ -38,7 +38,7 @@ import androidx.media3.common.Timeline; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.ConditionVariable; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -234,7 +234,7 @@ public class MockPlayer implements Player { @Nullable public SurfaceView surfaceView; @Nullable public TextureView textureView; public float volume; - public List cues; + public CueGroup cueGroup; public DeviceInfo deviceInfo; public int deviceVolume; public boolean deviceMuted; @@ -277,7 +277,7 @@ public class MockPlayer implements Player { repeatMode = Player.REPEAT_MODE_OFF; videoSize = VideoSize.UNKNOWN; volume = 1.0f; - cues = ImmutableList.of(); + cueGroup = CueGroup.EMPTY; deviceInfo = DeviceInfo.UNKNOWN; seekPositionMs = C.TIME_UNSET; seekMediaItemIndex = C.INDEX_UNSET; @@ -621,8 +621,8 @@ public class MockPlayer implements Player { } @Override - public List getCurrentCues() { - return cues; + public CueGroup getCurrentCues() { + return cueGroup; } @Override @@ -1134,9 +1134,11 @@ public class MockPlayer implements Player { } } + @SuppressWarnings("deprecation") // Implementing and calling deprecated listener method. public void notifyCuesChanged() { for (Listener listener : listeners) { - listener.onCues(cues); + listener.onCues(cueGroup.cues); + listener.onCues(cueGroup); } } diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaSession.java b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaSession.java index 4d6e3ace77..14d493be9f 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaSession.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaSession.java @@ -24,7 +24,7 @@ import static androidx.media3.test.session.common.CommonConstants.KEY_CONTENT_DU import static androidx.media3.test.session.common.CommonConstants.KEY_CONTENT_POSITION; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_AD_GROUP_INDEX; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_AD_INDEX_IN_AD_GROUP; -import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_CUES; +import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_CUE_GROUP; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_LIVE_OFFSET; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_MEDIA_ITEM_INDEX; import static androidx.media3.test.session.common.CommonConstants.KEY_CURRENT_PERIOD_INDEX; @@ -78,7 +78,7 @@ import androidx.media3.common.Player.PositionInfo; import androidx.media3.common.Timeline; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.BundleableUtil; import androidx.media3.common.util.Log; import androidx.media3.common.util.UnstableApi; @@ -389,8 +389,8 @@ public class RemoteMediaSession { binder.notifyDeviceVolumeChanged(sessionId, volume, muted); } - public void notifyCuesChanged(List cues) throws RemoteException { - binder.notifyCuesChanged(sessionId, BundleableUtil.toBundleList(cues)); + public void notifyCuesChanged(CueGroup cueGroup) throws RemoteException { + binder.notifyCuesChanged(sessionId, cueGroup.toBundle()); } public void notifyDeviceInfoChanged(DeviceInfo deviceInfo) throws RemoteException { @@ -595,8 +595,8 @@ public class RemoteMediaSession { return this; } - public MockPlayerConfigBuilder setCurrentCues(List cues) { - bundle.putParcelableArrayList(KEY_CURRENT_CUES, BundleableUtil.toBundleArrayList(cues)); + public MockPlayerConfigBuilder setCurrentCues(CueGroup cueGroup) { + bundle.putBundle(KEY_CURRENT_CUE_GROUP, cueGroup.toBundle()); return this; } diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/StubPlayer.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/StubPlayer.java index 849c3b417e..5787019136 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/StubPlayer.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/StubPlayer.java @@ -33,7 +33,7 @@ import androidx.media3.common.Timeline; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; -import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; import androidx.media3.common.util.UnstableApi; import java.util.List; @@ -346,7 +346,7 @@ public class StubPlayer extends BasePlayer { } @Override - public List getCurrentCues() { + public CueGroup getCurrentCues() { throw new UnsupportedOperationException(); } diff --git a/libraries/ui/src/main/java/androidx/media3/ui/PlayerView.java b/libraries/ui/src/main/java/androidx/media3/ui/PlayerView.java index b02e4b21cc..662d28e974 100644 --- a/libraries/ui/src/main/java/androidx/media3/ui/PlayerView.java +++ b/libraries/ui/src/main/java/androidx/media3/ui/PlayerView.java @@ -553,7 +553,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider { updateAspectRatio(); } if (subtitleView != null && player.isCommandAvailable(COMMAND_GET_TEXT)) { - subtitleView.setCues(player.getCurrentCues()); + subtitleView.setCues(player.getCurrentCues().cues); } player.addListener(componentListener); maybeShowController(false);