@@ -21,7 +21,6 @@ import org.junit.Before;
2121import org.junit.Rule;
2222import org.junit.Test;
2323import org.junit.rules.TestRule;
24- import org.junit.rules.Timeout;
2524import org.junit.rules.TestWatcher;
2625import org.junit.runner.RunWith;
2726import org.junit.runner.Description;
@@ -37,17 +36,11 @@ import org.robolectric.shadows.ShadowLooper;
3736@LooperMode(LooperMode.Mode.LEGACY)
3837public class @MAIN_NAME@UiTest {
3938
40- private static final long TEST_TIMEOUT_SECONDS = 300L;
39+ private static final long HANG_DETECTION_SECONDS = 300L;
4140
4241 private ActivityController<@MAIN_NAME@Stub> controller;
4342 private @MAIN_NAME@Stub activity;
4443
45- @Rule
46- public final TestRule timeoutRule = Timeout.builder()
47- .withTimeout(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS)
48- .withLookingForStuckThread(true)
49- .build();
50-
5144 @Rule
5245 public final TestWatcher loggingWatcher = new TestWatcher() {
5346 @Override
@@ -72,6 +65,9 @@ public class @MAIN_NAME@UiTest {
7265 }
7366 };
7467
68+ @Rule
69+ public final HangDetectionRule hangDetectionRule = new HangDetectionRule(HANG_DETECTION_SECONDS, TimeUnit.SECONDS);
70+
7571 @Before
7672 public void setUp() {
7773 log("Starting Robolectric activity for screenshot test");
@@ -285,4 +281,39 @@ public class @MAIN_NAME@UiTest {
285281 }
286282 });
287283 }
284+
285+ private static final class HangDetectionRule implements TestRule {
286+ private final long timeoutMillis;
287+
288+ HangDetectionRule(long timeout, TimeUnit unit) {
289+ this.timeoutMillis = unit.toMillis(timeout);
290+ }
291+
292+ @Override
293+ public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, Description description) {
294+ return new org.junit.runners.model.Statement() {
295+ @Override
296+ public void evaluate() throws Throwable {
297+ java.util.concurrent.ScheduledExecutorService executor = java.util.concurrent.Executors.newSingleThreadScheduledExecutor(r -> {
298+ Thread thread = new Thread(r, "@MAIN_NAME@UiTest-HangWatcher");
299+ thread.setDaemon(true);
300+ return thread;
301+ });
302+ java.util.concurrent.atomic.AtomicBoolean finished = new java.util.concurrent.atomic.AtomicBoolean(false);
303+ executor.schedule(() -> {
304+ if (!finished.get()) {
305+ log("Hang detection triggered after " + timeoutMillis + "ms");
306+ dumpAllThreads("Hang detection timeout");
307+ }
308+ }, timeoutMillis, TimeUnit.MILLISECONDS);
309+ try {
310+ base.evaluate();
311+ } finally {
312+ finished.set(true);
313+ executor.shutdownNow();
314+ }
315+ }
316+ };
317+ }
318+ }
288319}
0 commit comments