1 /* 2 * Copyright (C) 2016 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 */ 16 package android.fragment.cts; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertTrue; 20 21 import android.app.Activity; 22 import android.app.Fragment; 23 import android.app.FragmentController; 24 import android.app.FragmentManager; 25 import android.app.FragmentManagerNonConfig; 26 import android.os.Looper; 27 import android.os.Parcelable; 28 import android.support.test.rule.ActivityTestRule; 29 import android.util.Pair; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.view.accessibility.AccessibilityNodeInfo; 33 34 import java.util.concurrent.CountDownLatch; 35 import java.util.concurrent.TimeUnit; 36 37 public class FragmentTestUtil { waitForExecution(final ActivityTestRule<? extends Activity> rule)38 public static void waitForExecution(final ActivityTestRule<? extends Activity> rule) { 39 // Wait for two cycles. When starting a postponed transition, it will post to 40 // the UI thread and then the execution will be added onto the queue after that. 41 // The two-cycle wait makes sure fragments have the opportunity to complete both 42 // before returning. 43 try { 44 rule.runOnUiThread(() -> { 45 }); 46 rule.runOnUiThread(() -> { 47 }); 48 } catch (Throwable t) { 49 throw new RuntimeException(t); 50 } 51 } 52 runOnUiThreadRethrow(ActivityTestRule<? extends Activity> rule, Runnable r)53 private static void runOnUiThreadRethrow(ActivityTestRule<? extends Activity> rule, 54 Runnable r) { 55 if (Looper.getMainLooper() == Looper.myLooper()) { 56 r.run(); 57 } else { 58 try { 59 rule.runOnUiThread(r); 60 } catch (Throwable t) { 61 throw new RuntimeException(t); 62 } 63 } 64 } 65 executePendingTransactions( final ActivityTestRule<? extends Activity> rule)66 public static boolean executePendingTransactions( 67 final ActivityTestRule<? extends Activity> rule) { 68 return executePendingTransactions(rule, rule.getActivity().getFragmentManager()); 69 } 70 executePendingTransactions( final ActivityTestRule<? extends Activity> rule, final FragmentManager fm)71 public static boolean executePendingTransactions( 72 final ActivityTestRule<? extends Activity> rule, final FragmentManager fm) { 73 final boolean[] ret = new boolean[1]; 74 runOnUiThreadRethrow(rule, new Runnable() { 75 @Override 76 public void run() { 77 ret[0] = fm.executePendingTransactions(); 78 } 79 }); 80 return ret[0]; 81 } 82 popBackStackImmediate(final ActivityTestRule<? extends Activity> rule)83 public static boolean popBackStackImmediate(final ActivityTestRule<? extends Activity> rule) { 84 return popBackStackImmediate(rule, rule.getActivity().getFragmentManager()); 85 } 86 popBackStackImmediate(final ActivityTestRule<? extends Activity> rule, final FragmentManager fm)87 public static boolean popBackStackImmediate(final ActivityTestRule<? extends Activity> rule, 88 final FragmentManager fm) { 89 final boolean[] ret = new boolean[1]; 90 runOnUiThreadRethrow(rule, new Runnable() { 91 @Override 92 public void run() { 93 ret[0] = fm.popBackStackImmediate(); 94 } 95 }); 96 return ret[0]; 97 } 98 popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule, final int id, final int flags)99 public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule, 100 final int id, final int flags) { 101 return popBackStackImmediate(rule, rule.getActivity().getFragmentManager(), id, flags); 102 } 103 popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule, final FragmentManager fm, final int id, final int flags)104 public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule, 105 final FragmentManager fm, final int id, final int flags) { 106 final boolean[] ret = new boolean[1]; 107 runOnUiThreadRethrow(rule, new Runnable() { 108 @Override 109 public void run() { 110 ret[0] = fm.popBackStackImmediate(id, flags); 111 } 112 }); 113 return ret[0]; 114 } 115 popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule, final String name, final int flags)116 public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule, 117 final String name, final int flags) { 118 return popBackStackImmediate(rule, rule.getActivity().getFragmentManager(), name, flags); 119 } 120 popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule, final FragmentManager fm, final String name, final int flags)121 public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule, 122 final FragmentManager fm, final String name, final int flags) { 123 final boolean[] ret = new boolean[1]; 124 runOnUiThreadRethrow(rule, new Runnable() { 125 @Override 126 public void run() { 127 ret[0] = fm.popBackStackImmediate(name, flags); 128 } 129 }); 130 return ret[0]; 131 } 132 setContentView(final ActivityTestRule<FragmentTestActivity> rule, final int layoutId)133 public static void setContentView(final ActivityTestRule<FragmentTestActivity> rule, 134 final int layoutId) { 135 final Activity activity = rule.getActivity(); 136 runOnUiThreadRethrow(rule, new Runnable() { 137 @Override 138 public void run() { 139 activity.setContentView(layoutId); 140 } 141 }); 142 } 143 assertChildren(ViewGroup container, Fragment... fragments)144 public static void assertChildren(ViewGroup container, Fragment... fragments) { 145 final int numFragments = fragments == null ? 0 : fragments.length; 146 assertEquals("There aren't the correct number of fragment Views in its container", 147 numFragments, container.getChildCount()); 148 for (int i = 0; i < numFragments; i++) { 149 assertEquals("Wrong Fragment View order for [" + i + "]", container.getChildAt(i), 150 fragments[i].getView()); 151 } 152 } 153 createController(ActivityTestRule<FragmentTestActivity> rule)154 public static FragmentController createController(ActivityTestRule<FragmentTestActivity> rule) { 155 final FragmentController[] controller = new FragmentController[1]; 156 final FragmentTestActivity activity = rule.getActivity(); 157 runOnUiThreadRethrow(rule, () -> { 158 HostCallbacks hostCallbacks = new HostCallbacks(activity, null, 0); 159 controller[0] = FragmentController.createController(hostCallbacks); 160 }); 161 return controller[0]; 162 } 163 164 resume(ActivityTestRule<FragmentTestActivity> rule, FragmentController fragmentController, Pair<Parcelable, FragmentManagerNonConfig> savedState)165 public static void resume(ActivityTestRule<FragmentTestActivity> rule, 166 FragmentController fragmentController, 167 Pair<Parcelable, FragmentManagerNonConfig> savedState) { 168 runOnUiThreadRethrow(rule, () -> { 169 fragmentController.attachHost(null); 170 if (savedState != null) { 171 fragmentController.restoreAllState(savedState.first, savedState.second); 172 } 173 fragmentController.dispatchCreate(); 174 fragmentController.dispatchActivityCreated(); 175 fragmentController.noteStateNotSaved(); 176 fragmentController.execPendingActions(); 177 fragmentController.dispatchStart(); 178 fragmentController.reportLoaderStart(); 179 fragmentController.dispatchResume(); 180 fragmentController.execPendingActions(); 181 }); 182 } 183 destroy( ActivityTestRule<FragmentTestActivity> rule, FragmentController fragmentController)184 public static Pair<Parcelable, FragmentManagerNonConfig> destroy( 185 ActivityTestRule<FragmentTestActivity> rule, FragmentController fragmentController) { 186 final Pair<Parcelable, FragmentManagerNonConfig>[] result = new Pair[1]; 187 runOnUiThreadRethrow(rule, () -> { 188 fragmentController.dispatchPause(); 189 final Parcelable savedState = fragmentController.saveAllState(); 190 final FragmentManagerNonConfig nonConfig = fragmentController.retainNestedNonConfig(); 191 fragmentController.dispatchStop(); 192 fragmentController.doLoaderStop(false); 193 fragmentController.dispatchDestroy(); 194 fragmentController.doLoaderDestroy(); 195 result[0] = Pair.create(savedState, nonConfig); 196 }); 197 return result[0]; 198 } 199 isVisible(Fragment fragment)200 public static boolean isVisible(Fragment fragment) { 201 View view = fragment.getView(); 202 AccessibilityNodeInfo accessibilityNodeInfo = view.createAccessibilityNodeInfo(); 203 boolean isVisible = accessibilityNodeInfo.isVisibleToUser(); 204 accessibilityNodeInfo.recycle(); 205 return isVisible; 206 } 207 208 /** 209 * Allocates until a garbage collection occurs. 210 */ forceGC()211 public static void forceGC() { 212 // This works on ART: 213 Runtime.getRuntime().gc(); 214 Runtime.getRuntime().runFinalization(); 215 Runtime.getRuntime().gc(); 216 Runtime.getRuntime().runFinalization(); 217 } 218 219 /** 220 * Restarts the RecreatedActivity and waits for the new activity to be resumed. 221 * 222 * @return The newly-restarted Activity 223 */ recreateActivity( ActivityTestRule<? extends Activity> rule, T activity)224 public static <T extends RecreatedActivity> T recreateActivity( 225 ActivityTestRule<? extends Activity> rule, T activity) throws InterruptedException { 226 // Now switch the orientation 227 RecreatedActivity.sResumed = new CountDownLatch(1); 228 RecreatedActivity.sDestroyed = new CountDownLatch(1); 229 230 runOnUiThreadRethrow(rule, () -> { 231 activity.recreate(); 232 }); 233 assertTrue(RecreatedActivity.sResumed.await(1, TimeUnit.SECONDS)); 234 assertTrue(RecreatedActivity.sDestroyed.await(1, TimeUnit.SECONDS)); 235 T newActivity = (T) RecreatedActivity.sActivity; 236 237 waitForExecution(rule); 238 239 RecreatedActivity.clearState(); 240 return newActivity; 241 } 242 } 243 244 245