Commit a318e56d by tonihei Committed by Ian Baker

Fix FakeClock remove messages behaviour.

We currently only remove messages that have already been sent
to the actual Handler, not the pending ones that are only kept
in the FakeClock. Fix this by also removing matching messages
from the FakeClock list.

PiperOrigin-RevId: 353877049
parent 89ea38d1
...@@ -108,6 +108,27 @@ public class FakeClock implements Clock { ...@@ -108,6 +108,27 @@ public class FakeClock implements Clock {
maybeTriggerMessages(); maybeTriggerMessages();
} }
private synchronized void removePendingHandlerMessages(ClockHandler handler, int what) {
for (int i = handlerMessages.size() - 1; i >= 0; i--) {
HandlerMessage message = handlerMessages.get(i);
if (message.handler.equals(handler) && message.what == what) {
handlerMessages.remove(i);
}
}
handler.handler.removeMessages(what);
}
private synchronized void removePendingHandlerMessages(
ClockHandler handler, @Nullable Object token) {
for (int i = handlerMessages.size() - 1; i >= 0; i--) {
HandlerMessage message = handlerMessages.get(i);
if (message.handler.equals(handler) && (token == null || message.obj == token)) {
handlerMessages.remove(i);
}
}
handler.handler.removeCallbacksAndMessages(token);
}
private synchronized boolean hasPendingMessage(ClockHandler handler, int what) { private synchronized boolean hasPendingMessage(ClockHandler handler, int what) {
for (int i = 0; i < handlerMessages.size(); i++) { for (int i = 0; i < handlerMessages.size(); i++) {
HandlerMessage message = handlerMessages.get(i); HandlerMessage message = handlerMessages.get(i);
...@@ -261,12 +282,12 @@ public class FakeClock implements Clock { ...@@ -261,12 +282,12 @@ public class FakeClock implements Clock {
@Override @Override
public void removeMessages(int what) { public void removeMessages(int what) {
handler.removeMessages(what); removePendingHandlerMessages(/* handler= */ this, what);
} }
@Override @Override
public void removeCallbacksAndMessages(@Nullable Object token) { public void removeCallbacksAndMessages(@Nullable Object token) {
handler.removeCallbacksAndMessages(token); removePendingHandlerMessages(/* handler= */ this, token);
} }
@Override @Override
......
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.testutil; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.Shadows.shadowOf; import static org.robolectric.Shadows.shadowOf;
import android.os.ConditionVariable;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Message; import android.os.Message;
...@@ -186,6 +187,87 @@ public final class FakeClockTest { ...@@ -186,6 +187,87 @@ public final class FakeClockTest {
assertTestRunnableStates(new boolean[] {true, true, true, true, true}, testRunnables); assertTestRunnableStates(new boolean[] {true, true, true, true, true}, testRunnables);
} }
@Test
public void createHandler_removeMessages_removesMessages() {
HandlerThread handlerThread = new HandlerThread("FakeClockTest");
handlerThread.start();
FakeClock fakeClock = new FakeClock(/* initialTimeMs= */ 0);
TestCallback callback = new TestCallback();
HandlerWrapper handler = fakeClock.createHandler(handlerThread.getLooper(), callback);
TestCallback otherCallback = new TestCallback();
HandlerWrapper otherHandler = fakeClock.createHandler(handlerThread.getLooper(), otherCallback);
// Block any further execution on the HandlerThread until we had a chance to remove messages.
ConditionVariable startCondition = new ConditionVariable();
handler.post(startCondition::block);
TestRunnable testRunnable1 = new TestRunnable();
TestRunnable testRunnable2 = new TestRunnable();
Object messageToken = new Object();
handler.obtainMessage(/* what= */ 1, /* obj= */ messageToken).sendToTarget();
handler.sendEmptyMessageDelayed(/* what= */ 2, /* delayMs= */ 50);
handler.post(testRunnable1);
handler.postDelayed(testRunnable2, /* delayMs= */ 25);
handler.sendEmptyMessage(/* what= */ 3);
otherHandler.sendEmptyMessage(/* what= */ 2);
handler.removeMessages(/* what= */ 2);
handler.removeCallbacksAndMessages(messageToken);
startCondition.open();
fakeClock.advanceTime(50);
shadowOf(handlerThread.getLooper()).idle();
assertThat(callback.messages)
.containsExactly(
new MessageData(/* what= */ 3, /* arg1= */ 0, /* arg2= */ 0, /* obj=*/ null));
assertThat(testRunnable1.hasRun).isTrue();
assertThat(testRunnable2.hasRun).isTrue();
// Assert that message with same "what" on other handler wasn't removed.
assertThat(otherCallback.messages)
.containsExactly(
new MessageData(/* what= */ 2, /* arg1= */ 0, /* arg2= */ 0, /* obj=*/ null));
}
@Test
public void createHandler_removeAllMessages_removesAllMessages() {
HandlerThread handlerThread = new HandlerThread("FakeClockTest");
handlerThread.start();
FakeClock fakeClock = new FakeClock(/* initialTimeMs= */ 0);
TestCallback callback = new TestCallback();
HandlerWrapper handler = fakeClock.createHandler(handlerThread.getLooper(), callback);
TestCallback otherCallback = new TestCallback();
HandlerWrapper otherHandler = fakeClock.createHandler(handlerThread.getLooper(), otherCallback);
// Block any further execution on the HandlerThread until we had a chance to remove messages.
ConditionVariable startCondition = new ConditionVariable();
handler.post(startCondition::block);
TestRunnable testRunnable1 = new TestRunnable();
TestRunnable testRunnable2 = new TestRunnable();
Object messageToken = new Object();
handler.obtainMessage(/* what= */ 1, /* obj= */ messageToken).sendToTarget();
handler.sendEmptyMessageDelayed(/* what= */ 2, /* delayMs= */ 50);
handler.post(testRunnable1);
handler.postDelayed(testRunnable2, /* delayMs= */ 25);
handler.sendEmptyMessage(/* what= */ 3);
otherHandler.sendEmptyMessage(/* what= */ 1);
handler.removeCallbacksAndMessages(/* token= */ null);
startCondition.open();
fakeClock.advanceTime(50);
shadowOf(handlerThread.getLooper()).idle();
assertThat(callback.messages).isEmpty();
assertThat(testRunnable1.hasRun).isFalse();
assertThat(testRunnable2.hasRun).isFalse();
// Assert that message on other handler wasn't removed.
assertThat(otherCallback.messages)
.containsExactly(
new MessageData(/* what= */ 1, /* arg1= */ 0, /* arg2= */ 0, /* obj=*/ null));
}
private static void assertTestRunnableStates(boolean[] states, TestRunnable[] testRunnables) { private static void assertTestRunnableStates(boolean[] states, TestRunnable[] testRunnables) {
for (int i = 0; i < testRunnables.length; i++) { for (int i = 0; i < testRunnables.length; i++) {
assertThat(testRunnables[i].hasRun).isEqualTo(states[i]); assertThat(testRunnables[i].hasRun).isEqualTo(states[i]);
......
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