diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/idledetection/ReactIdleDetectionUtil.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/idledetection/ReactIdleDetectionUtil.java index 3b54f975acf..cb68061e1b1 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/idledetection/ReactIdleDetectionUtil.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/idledetection/ReactIdleDetectionUtil.java @@ -6,7 +6,14 @@ */ package com.facebook.react.testing.idledetection; +import android.app.Instrumentation; +import android.os.SystemClock; +import androidx.test.InstrumentationRegistry; import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.UiThreadUtil; +import com.facebook.react.modules.core.ChoreographerCompat; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class ReactIdleDetectionUtil { @@ -21,96 +28,93 @@ public class ReactIdleDetectionUtil { */ public static void waitForBridgeAndUIIdle( ReactBridgeIdleSignaler idleSignaler, final ReactContext reactContext, long timeoutMs) { + UiThreadUtil.assertNotOnUiThread(); - return; - // TODO: re-enable after cleanup of android-x migration - // UiThreadUtil.assertNotOnUiThread(); - // - // long startTime = SystemClock.uptimeMillis(); - // waitInner(idleSignaler, timeoutMs); - // - // long timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime)); - // waitForChoreographer(timeToWait); - // waitForJSIdle(reactContext); - // - // timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime)); - // waitInner(idleSignaler, timeToWait); - // timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime)); - // waitForChoreographer(timeToWait); + long startTime = SystemClock.uptimeMillis(); + waitInner(idleSignaler, timeoutMs); + + long timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime)); + waitForChoreographer(timeToWait); + waitForJSIdle(reactContext); + + timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime)); + waitInner(idleSignaler, timeToWait); + timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime)); + waitForChoreographer(timeToWait); } - // private static void waitForChoreographer(long timeToWait) { - // final int waitFrameCount = 2; - // final CountDownLatch latch = new CountDownLatch(1); - // UiThreadUtil.runOnUiThread( - // new Runnable() { - // @Override - // public void run() { - // final ChoreographerCompat choreographerCompat = ChoreographerCompat.getInstance(); - // choreographerCompat.postFrameCallback( - // new ChoreographerCompat.FrameCallback() { - // - // private int frameCount = 0; - // - // @Override - // public void doFrame(long frameTimeNanos) { - // frameCount++; - // if (frameCount == waitFrameCount) { - // latch.countDown(); - // } else { - // choreographerCompat.postFrameCallback(this); - // } - // } - // }); - // } - // }); - // try { - // if (!latch.await(timeToWait, TimeUnit.MILLISECONDS)) { - // throw new RuntimeException("Timed out waiting for Choreographer"); - // } - // } catch (Exception e) { - // throw new RuntimeException(e); - // } - // } - // - // private static void waitForJSIdle(ReactContext reactContext) { - // if (!reactContext.hasActiveCatalystInstance()) { - // return; - // } - // final CountDownLatch latch = new CountDownLatch(1); - // - // reactContext.runOnJSQueueThread( - // new Runnable() { - // @Override - // public void run() { - // latch.countDown(); - // } - // }); - // - // try { - // if (!latch.await(5000, TimeUnit.MILLISECONDS)) { - // throw new RuntimeException("Timed out waiting for JS thread"); - // } - // } catch (Exception e) { - // throw new RuntimeException(e); - // } - // } - // - // private static void waitInner(ReactBridgeIdleSignaler idleSignaler, long timeToWait) { - // // TODO gets broken in gradle, do we need it? - // Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); - // long startTime = SystemClock.uptimeMillis(); - // boolean bridgeWasIdle = false; - // while (SystemClock.uptimeMillis() - startTime < timeToWait) { - // boolean bridgeIsIdle = idleSignaler.isBridgeIdle(); - // if (bridgeIsIdle && bridgeWasIdle) { - // return; - // } - // bridgeWasIdle = bridgeIsIdle; - // long newTimeToWait = Math.max(1, timeToWait - (SystemClock.uptimeMillis() - startTime)); - // idleSignaler.waitForIdle(newTimeToWait); - // instrumentation.waitForIdleSync(); - // } - // throw new RuntimeException("Timed out waiting for bridge and UI idle!"); - // } + private static void waitForChoreographer(long timeToWait) { + final int waitFrameCount = 2; + final CountDownLatch latch = new CountDownLatch(1); + UiThreadUtil.runOnUiThread( + new Runnable() { + @Override + public void run() { + final ChoreographerCompat choreographerCompat = ChoreographerCompat.getInstance(); + choreographerCompat.postFrameCallback( + new ChoreographerCompat.FrameCallback() { + + private int frameCount = 0; + + @Override + public void doFrame(long frameTimeNanos) { + frameCount++; + if (frameCount == waitFrameCount) { + latch.countDown(); + } else { + choreographerCompat.postFrameCallback(this); + } + } + }); + } + }); + try { + if (!latch.await(timeToWait, TimeUnit.MILLISECONDS)) { + throw new RuntimeException("Timed out waiting for Choreographer"); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void waitForJSIdle(ReactContext reactContext) { + if (!reactContext.hasActiveCatalystInstance()) { + return; + } + final CountDownLatch latch = new CountDownLatch(1); + + reactContext.runOnJSQueueThread( + new Runnable() { + @Override + public void run() { + latch.countDown(); + } + }); + + try { + if (!latch.await(5000, TimeUnit.MILLISECONDS)) { + throw new RuntimeException("Timed out waiting for JS thread"); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void waitInner(ReactBridgeIdleSignaler idleSignaler, long timeToWait) { + // TODO gets broken in gradle, do we need it? + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + long startTime = SystemClock.uptimeMillis(); + boolean bridgeWasIdle = false; + while (SystemClock.uptimeMillis() - startTime < timeToWait) { + boolean bridgeIsIdle = idleSignaler.isBridgeIdle(); + if (bridgeIsIdle && bridgeWasIdle) { + return; + } + bridgeWasIdle = bridgeIsIdle; + long newTimeToWait = Math.max(1, timeToWait - (SystemClock.uptimeMillis() - startTime)); + idleSignaler.waitForIdle(newTimeToWait); + instrumentation.waitForIdleSync(); + } + throw new RuntimeException("Timed out waiting for bridge and UI idle!"); + } }