diff --git a/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/RobolectricUtil.java b/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/RobolectricUtil.java index bff6778b3f..c814bf3ce0 100644 --- a/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/RobolectricUtil.java +++ b/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/RobolectricUtil.java @@ -63,6 +63,12 @@ public final class RobolectricUtil { * *
Must be called on the main test thread. * + *
Note for {@link androidx.media3.test.utils.FakeClock} users: If the condition changes + * outside of a main {@link Looper} message, for example because it's checking a volatile variable + * or shared synchronized state that is updated on a background thread, or because checking the + * condition itself may cause it to become true, then the remainder of the test method may be + * executed in parallel with other background thread messages. + * * @param condition The condition. * @throws TimeoutException If the {@link #DEFAULT_TIMEOUT_MS} is exceeded. */ @@ -76,6 +82,12 @@ public final class RobolectricUtil { * *
Must be called on the main test thread. * + *
Note for {@link androidx.media3.test.utils.FakeClock} users: If the condition changes + * outside of a main {@link Looper} message, for example because it's checking a volatile variable + * or shared synchronized state that is updated on a background thread, or because checking the + * condition itself may cause it to become true, then the remainder of the test method may be + * executed in parallel with other background thread messages. + * * @param condition The condition. * @param timeoutMs The timeout in milliseconds. * @param clock The {@link Clock} to measure the timeout. @@ -91,6 +103,12 @@ public final class RobolectricUtil { * *
Must be called on the thread corresponding to the {@code looper}. * + *
Note for {@link androidx.media3.test.utils.FakeClock} users: If the condition changes + * outside of a message on this {@code Looper}, for example because it's checking a volatile + * variable or shared synchronized state that is updated on a background thread, or because + * checking the condition itself may cause it to become true, then the remainder of the test + * method may be executed in parallel with other background thread messages. + * * @param looper The {@link Looper}. * @param condition The condition. * @throws TimeoutException If the {@link #DEFAULT_TIMEOUT_MS} is exceeded. @@ -105,6 +123,12 @@ public final class RobolectricUtil { * *
Must be called on the thread corresponding to the {@code looper}. * + *
Note for {@link androidx.media3.test.utils.FakeClock} users: If the condition changes + * outside of a message on this {@code Looper}, for example because it's checking a volatile + * variable or shared synchronized state that is updated on a background thread, or because + * checking the condition itself may cause it to become true, then the remainder of the test + * method may be executed in parallel with other background thread messages. + * * @param looper The {@link Looper}. * @param condition The condition. * @param timeoutMs The timeout in milliseconds. diff --git a/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/TestPlayerRunHelper.java b/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/TestPlayerRunHelper.java index d9106acdbe..b28f4a92ee 100644 --- a/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/TestPlayerRunHelper.java +++ b/libraries/test_utils_robolectric/src/main/java/androidx/media3/test/utils/robolectric/TestPlayerRunHelper.java @@ -26,6 +26,7 @@ import androidx.media3.common.PlaybackException; import androidx.media3.common.Player; import androidx.media3.common.Timeline; import androidx.media3.common.util.ConditionVariable; +import androidx.media3.common.util.HandlerWrapper; import androidx.media3.common.util.NullableType; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -411,6 +412,47 @@ public final class TestPlayerRunHelper { runMainLooperUntil(receivedMessageCallback::get); } + /** + * Runs tasks of the main {@link Looper} until the specified condition becomes true independent + * of a message on the main {@link Looper}. + * + *
This method is useful for cases where the condition may change outside of a main {@link + * Looper} message, for example because it's checking a volatile variable or shared synchronized + * state that is updated on a background thread, or because checking the condition itself may + * cause it to become true. + * + *
This method ensures the condition is checked within artificially created main {@link
+ * Looper} messages. When using a {@link androidx.media3.test.utils.FakeClock}, this guarantees
+ * the remainder of the test method is not executed in parallel with other background thread
+ * messages.
+ *
+ * @param backgroundThreadCondition The condition to wait for.
+ * @throws TimeoutException If the {@link RobolectricUtil#DEFAULT_TIMEOUT_MS default timeout} is
+ * exceeded.
+ */
+ public void untilBackgroundThreadCondition(Supplier