Commit 33bea391 by tonihei Committed by microkatz

Ensure listener invocations use final state variable.

The MediaControllerImplBase listener invocations currently use the
class member state that can change if one of the listener method
implementations changes the state recursively.

Updating the listener invocations to use a final local variable
ensures all listeners get consistent updates.

PiperOrigin-RevId: 487503373
parent c6a0ba25
......@@ -22,7 +22,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.media3.common.Player;
import androidx.media3.common.Player.Commands;
import androidx.media3.common.util.BundleableUtil;
import androidx.media3.common.util.Log;
......@@ -180,11 +179,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
return;
}
dispatchControllerTaskOnHandler(
controller ->
controller.onPlayerInfoChanged(
playerInfo,
/* timelineChangedReason= */ Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
isTimelineExcluded));
controller -> controller.onPlayerInfoChanged(playerInfo, isTimelineExcluded));
}
@Override
......
......@@ -3300,6 +3300,44 @@ public class MediaControllerListenerTest {
assertThat(getEventsAsList(eventsRef.get())).containsExactly(Player.EVENT_RENDERED_FIRST_FRAME);
}
@Test
public void recursiveChangesFromListeners_reportConsistentValuesForAllListeners()
throws Exception {
// We add two listeners to the controller. The first stops the player as soon as it's ready and
// both record the state change events they receive.
MediaController controller = controllerTestRule.createController(remoteSession.getToken());
List<Integer> listener1States = new ArrayList<>();
List<Integer> listener2States = new ArrayList<>();
CountDownLatch latch = new CountDownLatch(4);
Player.Listener listener1 =
new Player.Listener() {
@Override
public void onPlaybackStateChanged(@Player.State int playbackState) {
listener1States.add(playbackState);
if (playbackState == Player.STATE_READY) {
controller.stop();
}
latch.countDown();
}
};
Player.Listener listener2 =
new Player.Listener() {
@Override
public void onPlaybackStateChanged(@Player.State int playbackState) {
listener2States.add(playbackState);
latch.countDown();
}
};
controller.addListener(listener1);
controller.addListener(listener2);
remoteSession.getMockPlayer().notifyPlaybackStateChanged(Player.STATE_READY);
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(listener1States).containsExactly(Player.STATE_READY, Player.STATE_IDLE).inOrder();
assertThat(listener2States).containsExactly(Player.STATE_READY, Player.STATE_IDLE).inOrder();
}
private void testControllerAfterSessionIsClosed(String id) throws Exception {
MediaController controller = controllerTestRule.createController(remoteSession.getToken());
// This causes the session service to die.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment