1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package androidx.testutils; 17 18import static org.junit.Assert.assertTrue; 19 20import android.app.Activity; 21import android.os.Looper; 22import android.support.test.rule.ActivityTestRule; 23 24import androidx.fragment.app.FragmentActivity; 25 26import java.util.concurrent.CountDownLatch; 27import java.util.concurrent.TimeUnit; 28 29/** 30 * Utility methods for testing fragment activities. 31 */ 32public class FragmentActivityUtils { 33 private static final Runnable DO_NOTHING = new Runnable() { 34 @Override 35 public void run() { 36 } 37 }; 38 39 private static void waitForExecution(final ActivityTestRule<? extends FragmentActivity> rule) { 40 // Wait for two cycles. When starting a postponed transition, it will post to 41 // the UI thread and then the execution will be added onto the queue after that. 42 // The two-cycle wait makes sure fragments have the opportunity to complete both 43 // before returning. 44 try { 45 rule.runOnUiThread(DO_NOTHING); 46 rule.runOnUiThread(DO_NOTHING); 47 } catch (Throwable throwable) { 48 throw new RuntimeException(throwable); 49 } 50 } 51 52 private static void runOnUiThreadRethrow(ActivityTestRule<? extends Activity> rule, 53 Runnable r) { 54 if (Looper.getMainLooper() == Looper.myLooper()) { 55 r.run(); 56 } else { 57 try { 58 rule.runOnUiThread(r); 59 } catch (Throwable t) { 60 throw new RuntimeException(t); 61 } 62 } 63 } 64 65 /** 66 * Restarts the RecreatedActivity and waits for the new activity to be resumed. 67 * 68 * @return The newly-restarted Activity 69 */ 70 public static <T extends RecreatedActivity> T recreateActivity( 71 ActivityTestRule<? extends RecreatedActivity> rule, final T activity) 72 throws InterruptedException { 73 // Now switch the orientation 74 RecreatedActivity.sResumed = new CountDownLatch(1); 75 RecreatedActivity.sDestroyed = new CountDownLatch(1); 76 77 runOnUiThreadRethrow(rule, new Runnable() { 78 @Override 79 public void run() { 80 activity.recreate(); 81 } 82 }); 83 assertTrue(RecreatedActivity.sResumed.await(1, TimeUnit.SECONDS)); 84 assertTrue(RecreatedActivity.sDestroyed.await(1, TimeUnit.SECONDS)); 85 T newActivity = (T) RecreatedActivity.sActivity; 86 87 waitForExecution(rule); 88 89 RecreatedActivity.clearState(); 90 return newActivity; 91 } 92 93 private FragmentActivityUtils() { 94 } 95} 96