Commit 0c3b1a64 by tonihei Committed by Andrew Lewis

Allow canceling player messages.

This adds a cancel method to PlayerMessage.

Issue:#4230

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=196638901
parent 8a0af84c
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* OkHttp extension: Fix to correctly include response headers in thrown * OkHttp extension: Fix to correctly include response headers in thrown
`InvalidResponseCodeException`s. `InvalidResponseCodeException`s.
* Add possibility to cancel `PlayerMessage`s.
* UI components: * UI components:
* Add `PlayerView.setKeepContentOnPlayerReset` to keep the currently displayed * Add `PlayerView.setKeepContentOnPlayerReset` to keep the currently displayed
video frame or media artwork visible when the player is reset video frame or media artwork visible when the player is reset
......
...@@ -854,6 +854,9 @@ import java.util.Collections; ...@@ -854,6 +854,9 @@ import java.util.Collections;
} }
private void deliverMessage(PlayerMessage message) throws ExoPlaybackException { private void deliverMessage(PlayerMessage message) throws ExoPlaybackException {
if (message.isCanceled()) {
return;
}
try { try {
message.getTarget().handleMessage(message.getType(), message.getPayload()); message.getTarget().handleMessage(message.getType(), message.getPayload());
} finally { } finally {
...@@ -945,7 +948,7 @@ import java.util.Collections; ...@@ -945,7 +948,7 @@ import java.util.Collections;
&& nextInfo.resolvedPeriodTimeUs > oldPeriodPositionUs && nextInfo.resolvedPeriodTimeUs > oldPeriodPositionUs
&& nextInfo.resolvedPeriodTimeUs <= newPeriodPositionUs) { && nextInfo.resolvedPeriodTimeUs <= newPeriodPositionUs) {
sendMessageToTarget(nextInfo.message); sendMessageToTarget(nextInfo.message);
if (nextInfo.message.getDeleteAfterDelivery()) { if (nextInfo.message.getDeleteAfterDelivery() || nextInfo.message.isCanceled()) {
pendingMessages.remove(nextPendingMessageIndex); pendingMessages.remove(nextPendingMessageIndex);
} else { } else {
nextPendingMessageIndex++; nextPendingMessageIndex++;
......
...@@ -63,6 +63,7 @@ public final class PlayerMessage { ...@@ -63,6 +63,7 @@ public final class PlayerMessage {
private boolean isSent; private boolean isSent;
private boolean isDelivered; private boolean isDelivered;
private boolean isProcessed; private boolean isProcessed;
private boolean isCanceled;
/** /**
* Creates a new message. * Creates a new message.
...@@ -243,6 +244,24 @@ public final class PlayerMessage { ...@@ -243,6 +244,24 @@ public final class PlayerMessage {
} }
/** /**
* Cancels the message delivery.
*
* @return This message.
* @throws IllegalStateException If this method is called before {@link #send()}.
*/
public synchronized PlayerMessage cancel() {
Assertions.checkState(isSent);
isCanceled = true;
markAsProcessed(/* isDelivered= */ false);
return this;
}
/** Returns whether the message delivery has been canceled. */
public synchronized boolean isCanceled() {
return isCanceled;
}
/**
* Blocks until after the message has been delivered or the player is no longer able to deliver * Blocks until after the message has been delivered or the player is no longer able to deliver
* the message. * the message.
* *
......
...@@ -51,6 +51,7 @@ import java.util.Arrays; ...@@ -51,6 +51,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
...@@ -1813,6 +1814,88 @@ public final class ExoPlayerTest { ...@@ -1813,6 +1814,88 @@ public final class ExoPlayerTest {
} }
@Test @Test
public void testCancelMessageBeforeDelivery() throws Exception {
Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
final PositionGrabbingMessageTarget target = new PositionGrabbingMessageTarget();
final AtomicReference<PlayerMessage> message = new AtomicReference<>();
ActionSchedule actionSchedule =
new ActionSchedule.Builder("testCancelMessage")
.pause()
.waitForPlaybackState(Player.STATE_BUFFERING)
.executeRunnable(
new PlayerRunnable() {
@Override
public void run(SimpleExoPlayer player) {
message.set(
player.createMessage(target).setPosition(/* positionMs= */ 50).send());
}
})
// Play a bit to ensure message arrived in internal player.
.playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 30)
.executeRunnable(
new Runnable() {
@Override
public void run() {
message.get().cancel();
}
})
.play()
.build();
new Builder()
.setTimeline(timeline)
.setActionSchedule(actionSchedule)
.build()
.start()
.blockUntilEnded(TIMEOUT_MS);
assertThat(message.get().isCanceled()).isTrue();
assertThat(target.messageCount).isEqualTo(0);
}
@Test
public void testCancelRepeatedMessageAfterDelivery() throws Exception {
Timeline timeline = new FakeTimeline(/* windowCount= */ 1);
final PositionGrabbingMessageTarget target = new PositionGrabbingMessageTarget();
final AtomicReference<PlayerMessage> message = new AtomicReference<>();
ActionSchedule actionSchedule =
new ActionSchedule.Builder("testCancelMessage")
.pause()
.waitForPlaybackState(Player.STATE_BUFFERING)
.executeRunnable(
new PlayerRunnable() {
@Override
public void run(SimpleExoPlayer player) {
message.set(
player
.createMessage(target)
.setPosition(/* positionMs= */ 50)
.setDeleteAfterDelivery(/* deleteAfterDelivery= */ false)
.send());
}
})
// Play until the message has been delivered.
.playUntilPosition(/* windowIndex= */ 0, /* positionMs= */ 51)
// Seek back, cancel the message, and play past the same position again.
.seek(/* positionMs= */ 0)
.executeRunnable(
new Runnable() {
@Override
public void run() {
message.get().cancel();
}
})
.play()
.build();
new Builder()
.setTimeline(timeline)
.setActionSchedule(actionSchedule)
.build()
.start()
.blockUntilEnded(TIMEOUT_MS);
assertThat(message.get().isCanceled()).isTrue();
assertThat(target.messageCount).isEqualTo(1);
}
@Test
public void testSetAndSwitchSurface() throws Exception { public void testSetAndSwitchSurface() throws Exception {
final List<Integer> rendererMessages = new ArrayList<>(); final List<Integer> rendererMessages = new ArrayList<>();
Renderer videoRenderer = Renderer videoRenderer =
...@@ -1934,8 +2017,10 @@ public final class ExoPlayerTest { ...@@ -1934,8 +2017,10 @@ public final class ExoPlayerTest {
@Override @Override
public void handleMessage(SimpleExoPlayer player, int messageType, Object message) { public void handleMessage(SimpleExoPlayer player, int messageType, Object message) {
if (player != null) {
windowIndex = player.getCurrentWindowIndex(); windowIndex = player.getCurrentWindowIndex();
positionMs = player.getCurrentPosition(); positionMs = player.getCurrentPosition();
}
messageCount++; messageCount++;
} }
} }
......
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