Merge "Convert utils to ActivityTestRule Kotlin extensions" into androidx-master-dev
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt
index 26ce615..c845318 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt
@@ -19,8 +19,10 @@
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.ActivityTestRule
-import androidx.testutils.FragmentActivityUtils
 import androidx.testutils.RecreatedActivity
+import androidx.testutils.recreate
+import androidx.testutils.runOnUiThreadRethrow
+import androidx.testutils.waitForExecution
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Rule
 import org.junit.Test
@@ -87,7 +89,7 @@
     fun testActivityDoesNotLeak() {
         // Restart the activity because activityRule keeps a strong reference to the
         // old activity.
-        val activity = FragmentActivityUtils.recreateActivity(activityRule, activityRule.activity)
+        val activity = activityRule.recreate()
         activityRule.runOnUiThreadRethrow {
             val parent = parentConfiguration.commit(activity.supportFragmentManager)!!
             childConfiguration.commit(parent.childFragmentManager)
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/ControllerHostCallbacks.kt b/fragment/src/androidTest/java/androidx/fragment/app/ControllerHostCallbacks.kt
index 59481c7..32a0f29 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/ControllerHostCallbacks.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/ControllerHostCallbacks.kt
@@ -25,6 +25,7 @@
 import androidx.lifecycle.ViewModelStore
 import androidx.lifecycle.ViewModelStoreOwner
 import androidx.test.rule.ActivityTestRule
+import androidx.testutils.runOnUiThreadRethrow
 import java.io.FileDescriptor
 import java.io.PrintWriter
 
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
index 4758b51..ced8cc8 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
@@ -34,6 +34,7 @@
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.ActivityTestRule
+import androidx.testutils.waitForExecution
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Rule
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
index f7c6400..d388bb2 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimatorTest.kt
@@ -30,6 +30,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import androidx.test.rule.ActivityTestRule
+import androidx.testutils.waitForExecution
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Rule
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerNonConfigTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerNonConfigTest.kt
index 6d47436..0c97102 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerNonConfigTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/FragmentManagerNonConfigTest.kt
@@ -22,7 +22,7 @@
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
 import androidx.test.rule.ActivityTestRule
-import androidx.testutils.FragmentActivityUtils
+import androidx.testutils.recreate
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -42,10 +42,7 @@
     @Test
     @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O_MR1)
     fun nonConfigStop() {
-        val activity = FragmentActivityUtils.recreateActivity(
-            activityRule,
-            activityRule.activity
-        )
+        val activity = activityRule.recreate()
 
         // A fragment was added in onStop(), but we shouldn't see it here...
         assertThat(activity.supportFragmentManager.fragments.isEmpty()).isTrue()
@@ -58,10 +55,7 @@
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
     fun nonConfigStopSavingFragment() {
-        val activity = FragmentActivityUtils.recreateActivity(
-            activityRule,
-            activityRule.activity
-        )
+        val activity = activityRule.recreate()
 
         assertThat(activity.supportFragmentManager.fragments.size).isEqualTo(1)
     }
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/FragmentSavedStateRegistryTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/FragmentSavedStateRegistryTest.kt
index cc85e34..8c3a55a 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/FragmentSavedStateRegistryTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/FragmentSavedStateRegistryTest.kt
@@ -25,8 +25,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.rule.ActivityTestRule
-import androidx.testutils.FragmentActivityUtils.recreateActivity
 import androidx.testutils.RecreatedActivity
+import androidx.testutils.recreate
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -55,7 +55,7 @@
     @Test
     fun savedState() {
         initializeSavedState()
-        val recreated = recreateActivity(activityRule, activityRule.activity)
+        val recreated = activityRule.recreate()
         activityRule.runOnUiThread {
             assertThat(recreated.fragment().lifecycle.currentState.isAtLeast(CREATED)).isTrue()
             checkDefaultSavedState(recreated.fragment().savedStateRegistry)
@@ -65,7 +65,7 @@
     @Test
     fun savedStateLateInit() {
         initializeSavedState()
-        val recreated = recreateActivity(activityRule, activityRule.activity)
+        val recreated = activityRule.recreate()
         activityRule.runOnUiThread {
             recreated.fragment().lifecycle.addObserver(object : LifecycleObserver {
                 @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
@@ -79,7 +79,7 @@
     @Test
     fun savedStateEarlyRegister() {
         initializeSavedState(OnCreateCheckingFragment())
-        recreateActivity(activityRule, activityRule.activity)
+        activityRule.recreate()
     }
 }
 
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTest.kt
index ae73917..600be6d 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTest.kt
@@ -31,6 +31,7 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.ActivityTestRule
+import androidx.testutils.waitForExecution
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Assert.fail
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTestUtil.kt b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTestUtil.kt
index 15eab40..689b4f6 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTestUtil.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTestUtil.kt
@@ -17,43 +17,16 @@
 
 import android.app.Activity
 import android.os.Build
-import android.os.Looper
 import android.view.ViewGroup
 import androidx.annotation.LayoutRes
 import androidx.test.core.app.ActivityScenario
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.ActivityTestRule
+import androidx.testutils.runOnUiThreadRethrow
 import com.google.common.truth.Truth.assertWithMessage
 import java.lang.ref.WeakReference
 import java.util.ArrayList
 
-fun ActivityTestRule<out FragmentActivity>.waitForExecution() {
-    // Wait for two cycles. When starting a postponed transition, it will post to
-    // the UI thread and then the execution will be added onto the queue after that.
-    // The two-cycle wait makes sure fragments have the opportunity to complete both
-    // before returning.
-    try {
-        runOnUiThread {}
-        runOnUiThread {}
-    } catch (throwable: Throwable) {
-        throw RuntimeException(throwable)
-    }
-}
-
-fun ActivityTestRule<out Activity>.runOnUiThreadRethrow(block: () -> Unit) {
-    if (Looper.getMainLooper() == Looper.myLooper()) {
-        block()
-    } else {
-        try {
-            runOnUiThread {
-                block()
-            }
-        } catch (t: Throwable) {
-            throw RuntimeException(t)
-        }
-    }
-}
-
 fun ActivityTestRule<out FragmentActivity>.executePendingTransactions(
     fm: FragmentManager = activity.supportFragmentManager
 ): Boolean {
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransactionTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransactionTest.kt
index 76074e0b..f9b6bd3 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransactionTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransactionTest.kt
@@ -23,13 +23,13 @@
 import androidx.fragment.app.FragmentManager
 import androidx.fragment.app.executePendingTransactions
 import androidx.fragment.app.popBackStackImmediate
-import androidx.fragment.app.waitForExecution
 import androidx.fragment.test.R
 import androidx.test.annotation.UiThreadTest
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.ActivityTestRule
+import androidx.testutils.waitForExecution
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.After
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
index 4233bdb..ae2397f 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
@@ -27,6 +27,7 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.ActivityTestRule
+import androidx.testutils.waitForExecution
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.After
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/HangingFragmentTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/HangingFragmentTest.kt
index fac2f35..f69379b 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/HangingFragmentTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/HangingFragmentTest.kt
@@ -20,7 +20,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.test.rule.ActivityTestRule
-import androidx.testutils.FragmentActivityUtils
+import androidx.testutils.recreate
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -35,9 +35,7 @@
 
     @Test
     fun testNoCrash() {
-        val newActivity = FragmentActivityUtils.recreateActivity(
-            activityRule, activityRule.activity
-        )
+        val newActivity = activityRule.recreate()
         assertThat(newActivity).isNotNull()
     }
 }
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/LoaderTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/LoaderTest.kt
index dddde5f..0d5ec16 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/LoaderTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/LoaderTest.kt
@@ -26,7 +26,8 @@
 import androidx.test.filters.MediumTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.ActivityTestRule
-import androidx.testutils.FragmentActivityUtils
+import androidx.testutils.recreate
+import androidx.testutils.waitForExecution
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -46,7 +47,7 @@
     fun testLeak() {
         // Restart the activity because activityRule keeps a strong reference to the
         // old activity.
-        val activity = FragmentActivityUtils.recreateActivity(activityRule, activityRule.activity)
+        val activity = activityRule.recreate()
 
         val fragment = LoaderFragment()
         val fm: FragmentManager = activity.supportFragmentManager
@@ -85,7 +86,7 @@
 
         assertThat(activity.textView.text).isEqualTo("Loaded!")
 
-        activity = FragmentActivityUtils.recreateActivity(activityRule, activity)
+        activity = activityRule.recreate()
 
         activityRule.waitForExecution()
 
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt b/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt
index b696d0c..6ca28bd 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt
+++ b/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt
@@ -28,6 +28,7 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.ActivityTestRule
+import androidx.testutils.waitForExecution
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Assert.fail
diff --git a/testutils/src/main/java/androidx/testutils/ActivityTestRule.kt b/testutils/src/main/java/androidx/testutils/ActivityTestRule.kt
new file mode 100644
index 0000000..ec1f15e
--- /dev/null
+++ b/testutils/src/main/java/androidx/testutils/ActivityTestRule.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.testutils
+
+import android.app.Activity
+import android.os.Looper
+import androidx.test.rule.ActivityTestRule
+
+/**
+ * Wait for execution, by default waiting 2 cycles to ensure that posted transitions are
+ * executed and have had a chance to run.
+ */
+fun ActivityTestRule<out Activity>.waitForExecution(cycles: Int = 2) {
+    // Wait for two cycles. When starting a postponed transition, it will post to
+    // the UI thread and then the execution will be added onto the queue after that.
+    // The two-cycle wait makes sure fragments have the opportunity to complete both
+    // before returning.
+    try {
+        for (i in 0 until cycles) {
+            runOnUiThreadRethrow {}
+        }
+    } catch (throwable: Throwable) {
+        throw RuntimeException(throwable)
+    }
+}
+
+fun ActivityTestRule<out Activity>.runOnUiThreadRethrow(block: () -> Unit) {
+    if (Looper.getMainLooper() == Looper.myLooper()) {
+        block()
+    } else {
+        try {
+            runOnUiThread {
+                block()
+            }
+        } catch (t: Throwable) {
+            throw RuntimeException(t)
+        }
+    }
+}
diff --git a/testutils/src/main/java/androidx/testutils/AppCompatActivityUtils.java b/testutils/src/main/java/androidx/testutils/AppCompatActivityUtils.java
deleted file mode 100644
index 6a749ce..0000000
--- a/testutils/src/main/java/androidx/testutils/AppCompatActivityUtils.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.testutils;
-
-import static org.junit.Assert.assertTrue;
-
-import android.os.Looper;
-
-import androidx.test.rule.ActivityTestRule;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Utility methods for testing AppCompat activities.
- */
-public class AppCompatActivityUtils {
-    private static final Runnable DO_NOTHING = new Runnable() {
-        @Override
-        public void run() {
-        }
-    };
-
-    /**
-     * Wait until the specified number of cycles have passed.
-     *
-     * @param cycles The number of cycles to wait
-     * @param rule The test's ActivityTestRule
-     */
-    public static void waitForCycles(final int cycles,
-            final ActivityTestRule<? extends RecreatedAppCompatActivity> rule) {
-        try {
-            for (int i = 0; i < cycles; i++) {
-                rule.runOnUiThread(DO_NOTHING);
-            }
-        } catch (Throwable throwable) {
-            throw new RuntimeException(throwable);
-        }
-    }
-
-    /**
-     * Waits for the execution of the provided activity test rule.
-     *
-     * @param rule Activity test rule to wait for
-     */
-    public static void waitForExecution(
-            final ActivityTestRule<? extends RecreatedAppCompatActivity> rule) {
-        // Wait for two cycles. When starting a postponed transition, it will post to
-        // the UI thread and then the execution will be added onto the queue after that.
-        // The two-cycle wait makes sure fragments have the opportunity to complete both
-        // before returning.
-        waitForCycles(2, rule);
-    }
-
-    private static void runOnUiThreadRethrow(
-            ActivityTestRule<? extends RecreatedAppCompatActivity> rule, Runnable r) {
-        if (Looper.getMainLooper() == Looper.myLooper()) {
-            r.run();
-        } else {
-            try {
-                rule.runOnUiThread(r);
-            } catch (Throwable t) {
-                throw new RuntimeException(t);
-            }
-        }
-    }
-
-    /**
-     * Restarts the RecreatedAppCompatActivity and waits for the new activity to be resumed.
-     *
-     * @return The newly-restarted RecreatedAppCompatActivity
-     */
-    public static <T extends RecreatedAppCompatActivity> T recreateActivity(
-            ActivityTestRule<? extends RecreatedAppCompatActivity> rule, final T activity)
-            throws InterruptedException {
-        // Now switch the orientation
-        RecreatedAppCompatActivity.setResumedLatch(new CountDownLatch(1));
-        RecreatedAppCompatActivity.setDestroyedLatch(new CountDownLatch(1));
-
-        runOnUiThreadRethrow(rule, new Runnable() {
-            @Override
-            public void run() {
-                activity.recreate();
-            }
-        });
-        assertTrue(RecreatedAppCompatActivity.getResumedLatch().await(1, TimeUnit.SECONDS));
-        assertTrue(RecreatedAppCompatActivity.getDestroyedLatch().await(1, TimeUnit.SECONDS));
-        T newActivity = (T) RecreatedAppCompatActivity.getActivity();
-
-        waitForExecution(rule);
-
-        RecreatedAppCompatActivity.clearState();
-        return newActivity;
-    }
-
-    private AppCompatActivityUtils() {
-    }
-}
diff --git a/testutils/src/main/java/androidx/testutils/FragmentActivityUtils.java b/testutils/src/main/java/androidx/testutils/FragmentActivityUtils.java
deleted file mode 100644
index b709b38..0000000
--- a/testutils/src/main/java/androidx/testutils/FragmentActivityUtils.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.testutils;
-
-import static org.junit.Assert.assertTrue;
-
-import android.app.Activity;
-import android.os.Looper;
-
-import androidx.fragment.app.FragmentActivity;
-import androidx.test.rule.ActivityTestRule;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Utility methods for testing fragment activities.
- */
-public class FragmentActivityUtils {
-    private static final Runnable DO_NOTHING = new Runnable() {
-        @Override
-        public void run() {
-        }
-    };
-
-    /**
-     * Wait until the specified number of cycles have passed.
-     *
-     * @param cycles The number of cycles to wait
-     * @param rule The test's ActivityTestRule
-     */
-    public static void waitForCycles(final int cycles,
-            final ActivityTestRule<? extends FragmentActivity> rule) {
-        try {
-            for (int i = 0; i < cycles; i++) {
-                rule.runOnUiThread(DO_NOTHING);
-            }
-        } catch (Throwable throwable) {
-            throw new RuntimeException(throwable);
-        }
-    }
-
-    /**
-     * Waits for the execution of the provided activity test rule.
-     *
-     * @param rule Activity test rule to wait for
-     */
-    public static void waitForExecution(final ActivityTestRule<? extends FragmentActivity> rule) {
-        // Wait for two cycles. When starting a postponed transition, it will post to
-        // the UI thread and then the execution will be added onto the queue after that.
-        // The two-cycle wait makes sure fragments have the opportunity to complete both
-        // before returning.
-        waitForCycles(2, rule);
-    }
-
-    private static void runOnUiThreadRethrow(ActivityTestRule<? extends Activity> rule,
-            Runnable r) {
-        if (Looper.getMainLooper() == Looper.myLooper()) {
-            r.run();
-        } else {
-            try {
-                rule.runOnUiThread(r);
-            } catch (Throwable t) {
-                throw new RuntimeException(t);
-            }
-        }
-    }
-
-    /**
-     * Restarts the RecreatedActivity and waits for the new activity to be resumed.
-     *
-     * @return The newly-restarted Activity
-     */
-    public static <T extends RecreatedActivity> T recreateActivity(
-            ActivityTestRule<? extends RecreatedActivity> rule, final T activity)
-            throws InterruptedException {
-        // Now switch the orientation
-        RecreatedActivity.setResumedLatch(new CountDownLatch(1));
-        RecreatedActivity.setDestroyedLatch(new CountDownLatch(1));
-
-        runOnUiThreadRethrow(rule, new Runnable() {
-            @Override
-            public void run() {
-                activity.recreate();
-            }
-        });
-        assertTrue(RecreatedActivity.getResumedLatch().await(1, TimeUnit.SECONDS));
-        assertTrue(RecreatedActivity.getDestroyedLatch().await(1, TimeUnit.SECONDS));
-        T newActivity = (T) RecreatedActivity.getActivity();
-
-        waitForExecution(rule);
-
-        RecreatedActivity.clearState();
-        return newActivity;
-    }
-
-    private FragmentActivityUtils() {
-    }
-}
diff --git a/testutils/src/main/java/androidx/testutils/RecreatedActivity.kt b/testutils/src/main/java/androidx/testutils/RecreatedActivity.kt
index 1463395..8c02fc8 100644
--- a/testutils/src/main/java/androidx/testutils/RecreatedActivity.kt
+++ b/testutils/src/main/java/androidx/testutils/RecreatedActivity.kt
@@ -19,12 +19,15 @@
 import android.os.Bundle
 import androidx.annotation.LayoutRes
 import androidx.fragment.app.FragmentActivity
+import androidx.test.rule.ActivityTestRule
+import org.junit.Assert
 import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 
 /**
  * Extension of [FragmentActivity] that keeps track of when it is recreated.
  * In order to use this class, have your activity extend it and call
- * [FragmentActivityUtils.recreateActivity] API.
+ * [recreate] API.
  */
 open class RecreatedActivity(
     @LayoutRes contentLayoutId: Int = 0
@@ -46,19 +49,40 @@
     }
 
     companion object {
-        // These must be cleared after each test using clearState()
         @JvmStatic
         var activity: RecreatedActivity? = null
         @JvmStatic
-        var resumedLatch: CountDownLatch? = null
+        internal var resumedLatch: CountDownLatch? = null
         @JvmStatic
-        var destroyedLatch: CountDownLatch? = null
+        internal var destroyedLatch: CountDownLatch? = null
 
         @JvmStatic
-        fun clearState() {
+        internal fun clearState() {
             activity = null
             resumedLatch = null
             destroyedLatch = null
         }
     }
 }
+
+/**
+ * Restarts the [RecreatedActivity] and waits for the new activity to be resumed.
+ *
+ * @return The newly-restarted [RecreatedActivity]
+ */
+@Suppress("UNCHECKED_CAST")
+fun <T : RecreatedActivity> ActivityTestRule<T>.recreate(): T {
+    // Now switch the orientation
+    RecreatedActivity.resumedLatch = CountDownLatch(1)
+    RecreatedActivity.destroyedLatch = CountDownLatch(1)
+
+    runOnUiThreadRethrow { activity.recreate() }
+    Assert.assertTrue(RecreatedActivity.resumedLatch!!.await(1, TimeUnit.SECONDS))
+    Assert.assertTrue(RecreatedActivity.destroyedLatch!!.await(1, TimeUnit.SECONDS))
+    val newActivity = RecreatedActivity.activity as T
+
+    waitForExecution()
+
+    RecreatedActivity.clearState()
+    return newActivity
+}
diff --git a/testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.kt b/testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.kt
index 49bc914..b577fc2 100644
--- a/testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.kt
+++ b/testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.kt
@@ -19,12 +19,15 @@
 import android.os.Bundle
 import androidx.annotation.LayoutRes
 import androidx.appcompat.app.AppCompatActivity
+import androidx.test.rule.ActivityTestRule
+import org.junit.Assert.assertTrue
 import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 
 /**
  * Extension of [AppCompatActivity] that keeps track of when it is recreated.
  * In order to use this class, have your activity extend it and call
- * [AppCompatActivityUtils.recreateActivity] API.
+ * [recreate] API.
  */
 open class RecreatedAppCompatActivity(
     @LayoutRes contentLayoutId: Int = 0
@@ -46,19 +49,40 @@
     }
 
     companion object {
-        // These must be cleared after each test using clearState()
         @JvmStatic
         var activity: RecreatedAppCompatActivity? = null
         @JvmStatic
-        var resumedLatch: CountDownLatch? = null
+        internal var resumedLatch: CountDownLatch? = null
         @JvmStatic
-        var destroyedLatch: CountDownLatch? = null
+        internal var destroyedLatch: CountDownLatch? = null
 
         @JvmStatic
-        fun clearState() {
+        internal fun clearState() {
             activity = null
             resumedLatch = null
             destroyedLatch = null
         }
     }
 }
+
+/**
+ * Restarts the [RecreatedAppCompatActivity] and waits for the new activity to be resumed.
+ *
+ * @return The newly-restarted [RecreatedAppCompatActivity]
+ */
+@Suppress("UNCHECKED_CAST")
+fun <T : RecreatedAppCompatActivity> ActivityTestRule<T>.recreate(): T {
+    // Now switch the orientation
+    RecreatedAppCompatActivity.resumedLatch = CountDownLatch(1)
+    RecreatedAppCompatActivity.destroyedLatch = CountDownLatch(1)
+
+    runOnUiThreadRethrow { activity.recreate() }
+    assertTrue(RecreatedAppCompatActivity.resumedLatch!!.await(1, TimeUnit.SECONDS))
+    assertTrue(RecreatedAppCompatActivity.destroyedLatch!!.await(1, TimeUnit.SECONDS))
+    val newActivity = RecreatedAppCompatActivity.activity as T
+
+    waitForExecution()
+
+    RecreatedAppCompatActivity.clearState()
+    return newActivity
+}
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
index 0f2f78c..f548ced 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
@@ -39,8 +39,8 @@
 import androidx.test.espresso.matcher.ViewMatchers.withId
 import androidx.test.espresso.matcher.ViewMatchers.withText
 import androidx.test.rule.ActivityTestRule
-import androidx.testutils.AppCompatActivityUtils
 import androidx.testutils.LocaleTestUtils
+import androidx.testutils.recreate
 import androidx.viewpager2.adapter.FragmentStateAdapter
 import androidx.viewpager2.test.R
 import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
@@ -137,7 +137,7 @@
                 viewPager.adapter = adapterProvider(activity)
                 onCreateCallback(viewPager)
             }
-            activity = AppCompatActivityUtils.recreateActivity(activityTestRule, activity)
+            activity = activityTestRule.recreate()
             TestActivity.onCreateCallback = { }
             onView(withId(R.id.view_pager)).perform(waitForInjectMotionEvents())
         }
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt
index 0e2e9a9..fb2abd3 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/DisableUserInputTest.kt
@@ -19,7 +19,7 @@
 import androidx.recyclerview.widget.RecyclerView
 import androidx.test.filters.LargeTest
 import androidx.test.filters.MediumTest
-import androidx.testutils.FragmentActivityUtils.waitForCycles
+import androidx.testutils.waitForExecution
 import androidx.viewpager2.test.ui.TouchConsumingTextView
 import androidx.viewpager2.widget.DisableUserInputTest.Event.OnPageScrollStateChangedEvent
 import androidx.viewpager2.widget.DisableUserInputTest.Event.OnPageScrolledEvent
@@ -102,7 +102,7 @@
 
         // when
         test.swipe(currentPage, targetPage)
-        waitForCycles(3, test.activityTestRule)
+        test.activityTestRule.waitForExecution(3)
 
         // then
         test.assertBasicState(currentPage)
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
index a7a4e17..00494c2 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
@@ -23,8 +23,8 @@
 import android.view.animation.LinearInterpolator
 import androidx.core.view.animation.PathInterpolatorCompat
 import androidx.test.filters.LargeTest
-import androidx.testutils.FragmentActivityUtils.waitForCycles
 import androidx.testutils.LocaleTestUtils
+import androidx.testutils.waitForExecution
 import androidx.viewpager2.widget.BaseTest.Context.SwipeMethod
 import androidx.viewpager2.widget.FakeDragTest.Event.OnPageScrollStateChangedEvent
 import androidx.viewpager2.widget.FakeDragTest.Event.OnPageScrolledEvent
@@ -346,7 +346,7 @@
             test.viewPager.setCurrentItemSync(initialPage, false, 2, SECONDS)
             // VP2 was potentially settling while the RetryException was raised, in which case we
             // must wait until the IDLE event has been fired
-            waitForCycles(1, activityTestRule)
+            activityTestRule.waitForExecution(1)
         }) { /* TRY block */
             val recorder = test.viewPager.addNewRecordingCallback()