Commit 55cc0df5 by tonihei Committed by Oliver Woodman

Create actual copy of listener list instead of just copying the reference.

Forwarding the listeners to the notification update is meant to ensure we
only notify the listeners which were registered at the time the event happened

However, we currently just copy the reference to the actual list instead of
doing a deep copy of the listeners.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=222227735
parent b7ab5700
...@@ -37,8 +37,7 @@ import com.google.android.exoplayer2.util.Util; ...@@ -37,8 +37,7 @@ import com.google.android.exoplayer2.util.Util;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
/** An {@link ExoPlayer} implementation. Instances can be obtained from {@link ExoPlayerFactory}. */ /** An {@link ExoPlayer} implementation. Instances can be obtained from {@link ExoPlayerFactory}. */
/* package */ final class ExoPlayerImpl extends BasePlayer implements ExoPlayer { /* package */ final class ExoPlayerImpl extends BasePlayer implements ExoPlayer {
...@@ -59,7 +58,7 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -59,7 +58,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private final Handler eventHandler; private final Handler eventHandler;
private final ExoPlayerImplInternal internalPlayer; private final ExoPlayerImplInternal internalPlayer;
private final Handler internalPlayerHandler; private final Handler internalPlayerHandler;
private final CopyOnWriteArraySet<Player.EventListener> listeners; private final CopyOnWriteArrayList<ListenerHolder> listeners;
private final Timeline.Period period; private final Timeline.Period period;
private final ArrayDeque<Runnable> pendingListenerNotifications; private final ArrayDeque<Runnable> pendingListenerNotifications;
...@@ -111,7 +110,7 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -111,7 +110,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
this.playWhenReady = false; this.playWhenReady = false;
this.repeatMode = Player.REPEAT_MODE_OFF; this.repeatMode = Player.REPEAT_MODE_OFF;
this.shuffleModeEnabled = false; this.shuffleModeEnabled = false;
this.listeners = new CopyOnWriteArraySet<>(); this.listeners = new CopyOnWriteArrayList<>();
emptyTrackSelectorResult = emptyTrackSelectorResult =
new TrackSelectorResult( new TrackSelectorResult(
new RendererConfiguration[renderers.length], new RendererConfiguration[renderers.length],
...@@ -172,12 +171,17 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -172,12 +171,17 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public void addListener(Player.EventListener listener) { public void addListener(Player.EventListener listener) {
listeners.add(listener); listeners.addIfAbsent(new ListenerHolder(listener));
} }
@Override @Override
public void removeListener(Player.EventListener listener) { public void removeListener(Player.EventListener listener) {
listeners.remove(listener); for (ListenerHolder listenerHolder : listeners) {
if (listenerHolder.listener.equals(listener)) {
listenerHolder.release();
listeners.remove(listenerHolder);
}
}
} }
@Override @Override
...@@ -694,12 +698,8 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -694,12 +698,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
} }
private void notifyListeners(ListenerInvocation listenerInvocation) { private void notifyListeners(ListenerInvocation listenerInvocation) {
notifyListeners( CopyOnWriteArrayList<ListenerHolder> listenerSnapshot = new CopyOnWriteArrayList<>(listeners);
() -> { notifyListeners(() -> invokeAll(listenerSnapshot, listenerInvocation));
for (Player.EventListener listener : listeners) {
listenerInvocation.invokeListener(listener);
}
});
} }
private void notifyListeners(Runnable listenerNotificationRunnable) { private void notifyListeners(Runnable listenerNotificationRunnable) {
...@@ -728,7 +728,7 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -728,7 +728,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private static final class PlaybackInfoUpdate implements Runnable { private static final class PlaybackInfoUpdate implements Runnable {
private final PlaybackInfo playbackInfo; private final PlaybackInfo playbackInfo;
private final Set<Player.EventListener> listeners; private final CopyOnWriteArrayList<ListenerHolder> listenerSnapshot;
private final TrackSelector trackSelector; private final TrackSelector trackSelector;
private final boolean positionDiscontinuity; private final boolean positionDiscontinuity;
private final @Player.DiscontinuityReason int positionDiscontinuityReason; private final @Player.DiscontinuityReason int positionDiscontinuityReason;
...@@ -743,7 +743,7 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -743,7 +743,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
public PlaybackInfoUpdate( public PlaybackInfoUpdate(
PlaybackInfo playbackInfo, PlaybackInfo playbackInfo,
PlaybackInfo previousPlaybackInfo, PlaybackInfo previousPlaybackInfo,
Set<Player.EventListener> listeners, CopyOnWriteArrayList<ListenerHolder> listeners,
TrackSelector trackSelector, TrackSelector trackSelector,
boolean positionDiscontinuity, boolean positionDiscontinuity,
@Player.DiscontinuityReason int positionDiscontinuityReason, @Player.DiscontinuityReason int positionDiscontinuityReason,
...@@ -751,7 +751,7 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -751,7 +751,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
boolean seekProcessed, boolean seekProcessed,
boolean playWhenReady) { boolean playWhenReady) {
this.playbackInfo = playbackInfo; this.playbackInfo = playbackInfo;
this.listeners = listeners; this.listenerSnapshot = new CopyOnWriteArrayList<>(listeners);
this.trackSelector = trackSelector; this.trackSelector = trackSelector;
this.positionDiscontinuity = positionDiscontinuity; this.positionDiscontinuity = positionDiscontinuity;
this.positionDiscontinuityReason = positionDiscontinuityReason; this.positionDiscontinuityReason = positionDiscontinuityReason;
...@@ -770,43 +770,85 @@ import java.util.concurrent.CopyOnWriteArraySet; ...@@ -770,43 +770,85 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public void run() { public void run() {
if (timelineOrManifestChanged || timelineChangeReason == TIMELINE_CHANGE_REASON_PREPARED) { if (timelineOrManifestChanged || timelineChangeReason == TIMELINE_CHANGE_REASON_PREPARED) {
for (Player.EventListener listener : listeners) { invokeAll(
listener.onTimelineChanged( listenerSnapshot,
playbackInfo.timeline, playbackInfo.manifest, timelineChangeReason); listener ->
} listener.onTimelineChanged(
playbackInfo.timeline, playbackInfo.manifest, timelineChangeReason));
} }
if (positionDiscontinuity) { if (positionDiscontinuity) {
for (Player.EventListener listener : listeners) { invokeAll(
listener.onPositionDiscontinuity(positionDiscontinuityReason); listenerSnapshot,
} listener -> listener.onPositionDiscontinuity(positionDiscontinuityReason));
} }
if (trackSelectorResultChanged) { if (trackSelectorResultChanged) {
trackSelector.onSelectionActivated(playbackInfo.trackSelectorResult.info); trackSelector.onSelectionActivated(playbackInfo.trackSelectorResult.info);
for (Player.EventListener listener : listeners) { invokeAll(
listener.onTracksChanged( listenerSnapshot,
playbackInfo.trackGroups, playbackInfo.trackSelectorResult.selections); listener ->
} listener.onTracksChanged(
playbackInfo.trackGroups, playbackInfo.trackSelectorResult.selections));
} }
if (isLoadingChanged) { if (isLoadingChanged) {
for (Player.EventListener listener : listeners) { invokeAll(listenerSnapshot, listener -> listener.onLoadingChanged(playbackInfo.isLoading));
listener.onLoadingChanged(playbackInfo.isLoading);
}
} }
if (playbackStateChanged) { if (playbackStateChanged) {
for (Player.EventListener listener : listeners) { invokeAll(
listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState); listenerSnapshot,
} listener -> listener.onPlayerStateChanged(playWhenReady, playbackInfo.playbackState));
} }
if (seekProcessed) { if (seekProcessed) {
for (Player.EventListener listener : listeners) { invokeAll(listenerSnapshot, EventListener::onSeekProcessed);
listener.onSeekProcessed();
}
} }
} }
} }
private static void invokeAll(
CopyOnWriteArrayList<ListenerHolder> listeners, ListenerInvocation listenerInvocation) {
for (ListenerHolder listenerHolder : listeners) {
listenerHolder.invoke(listenerInvocation);
}
}
private interface ListenerInvocation { private interface ListenerInvocation {
void invokeListener(Player.EventListener listener); void invokeListener(Player.EventListener listener);
} }
private static final class ListenerHolder {
private final Player.EventListener listener;
private boolean released;
public ListenerHolder(Player.EventListener listener) {
this.listener = listener;
}
public void release() {
released = true;
}
public void invoke(ListenerInvocation listenerInvocation) {
if (!released) {
listenerInvocation.invokeListener(listener);
}
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
return listener.equals(((ListenerHolder) other).listener);
}
@Override
public int hashCode() {
return listener.hashCode();
}
}
} }
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