下面列出了android.app.Instrumentation#waitForIdleSync ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
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!");
}
/**
* Opens the context menu for the provided {@link View} and invokes the menu item with the
* provided ID.
*
* <p>Note: This method cannot be invoked on the main thread.
*/
public static void openContextMenuAndInvokeItem(
Instrumentation instrumentation, final Activity activity, final View view, final int itemId) {
// IMPLEMENTATION NOTE: Instrumentation.invokeContextMenuAction would've been much simpler, but
// it requires the View to be focused which is hard to achieve in touch mode.
runOnMainSyncWithTimeout(
new Callable<Void>() {
@Override
public Void call() {
// Use performLongClick instead of showContextMenu to exercise more of the code path
// that
// is invoked when the user normally opens a context menu.
if (!view.performLongClick()) {
throw new RuntimeException("Failed to perform long click");
}
if (!activity.getWindow().performContextMenuIdentifierAction(itemId, 0)) {
throw new RuntimeException("Failed perform to context menu action");
}
return null;
}
});
instrumentation.waitForIdleSync();
}
@Test
public void testNavigateInOnResume() throws Throwable {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
Intent intent = new Intent(instrumentation.getContext(),
ImmediateNavigationActivity.class);
final ImmediateNavigationActivity activity = mActivityRule.launchActivity(intent);
instrumentation.waitForIdleSync();
NavController navController = activity.getNavController();
assertThat(navController.getCurrentDestination().getId(), is(R.id.deep_link_test));
}
@Test
public void testRecreate() throws Throwable {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
Intent intent = new Intent(instrumentation.getContext(),
EmbeddedXmlActivity.class);
final EmbeddedXmlActivity activity = mActivityRule.launchActivity(intent);
instrumentation.waitForIdleSync();
mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.recreate();
}
});
}
public static void click(Point location) {
final long time = SystemClock.uptimeMillis();
final MotionEvent actionDownEvent =
MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, location.x, location.y, 0);
final MotionEvent actionUpEvent =
MotionEvent.obtain(
time + 100, time + 100, MotionEvent.ACTION_UP, location.x, location.y, 0);
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
instrumentation.sendPointerSync(actionDownEvent);
instrumentation.sendPointerSync(actionUpEvent);
instrumentation.waitForIdleSync();
}
/** Set the Component for the Activity to display. */
public void setComponent(final Component component) {
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
instrumentation.runOnMainSync(
new Runnable() {
@Override
public void run() {
getActivity().setComponent(component);
}
});
instrumentation.waitForIdleSync();
}
/** Set ComponentTree for the Activity to display. */
public void setComponentTree(final ComponentTree componentTree) {
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
instrumentation.runOnMainSync(
new Runnable() {
@Override
public void run() {
getActivity().setComponentTree(componentTree);
}
});
instrumentation.waitForIdleSync();
}
private void startActivity() {
if (launched)
return;
Instrumentation instrumentation = getInstrumentation();
Intent intent = new Intent(getInstrumentation()
.getTargetContext(), AndroidNativeActivity.class);
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
mActivity = instrumentation.startActivitySync(intent);
launched = true;
instrumentation.waitForIdleSync();
sleep(5000);
}
private static boolean closeActivities(Instrumentation instrumentation) throws Exception {
final AtomicReference<Boolean> activityClosed = new AtomicReference<>();
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
public void run() {
/* Activities in android v8 never get destroyed, only stay in Stage.STOPPED ,*/
final Set<Activity> activities = getActivitiesInStages(Stage.RESUMED, Stage.STARTED, Stage.PAUSED, Stage.CREATED);
activities.removeAll(getActivitiesInStages(Stage.DESTROYED));
if (activities.size() > 0) {
for (Activity activity : activities) {
if (activity.isFinishing()) {
Log.i("espressotools", "activity in finishing state " + activity);
} else {
Log.i("espressotools", "activity not finished " + activity);
activity.finish();
}
}
activityClosed.set(true);
} else {
activityClosed.set(false);
}
}
});
if (activityClosed.get()) {
instrumentation.waitForIdleSync();
}
return activityClosed.get();
}
private void emulateButtonClick(
Instrumentation instrumentation, float emulatedTapX, float emulatedTapY) {
// Note that the reason to not use Espresso's click() view action is so that we can
// faithfully emulate what was happening in the reported bug. We don't want the events
// to be sent directly to the button, but rather be processed by the parent coordinator
// layout, so that we reproduce what is happening as the events are processed at the level
// of that parent.
// Inject DOWN event
long downTime = SystemClock.uptimeMillis();
MotionEvent eventDown =
MotionEvent.obtain(
downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
instrumentation.sendPointerSync(eventDown);
// Inject MOVE event
long moveTime = SystemClock.uptimeMillis();
MotionEvent eventMove =
MotionEvent.obtain(
moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedTapX, emulatedTapY, 1);
instrumentation.sendPointerSync(eventMove);
// Inject UP event
long upTime = SystemClock.uptimeMillis();
MotionEvent eventUp =
MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
instrumentation.sendPointerSync(eventUp);
// Wait for the system to process all events in the queue
instrumentation.waitForIdleSync();
}
@SuppressWarnings("unchecked") // Guarded by generics at the constructor.
public void launchActivity() {
if(activity != null) {
return;
}
Instrumentation instrumentation = fetchInstrumentation();
String targetPackage = instrumentation.getTargetContext().getPackageName();
Intent intent = getLaunchIntent(targetPackage, activityClass);
activity = (T) instrumentation.startActivitySync(intent);
instrumentation.waitForIdleSync();
}
public AppLaunchInteractor launchApp() {
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
final Intent launchIntent = instrumentation.getTargetContext().getPackageManager()
.getLaunchIntentForPackage(instrumentation.getTargetContext().getPackageName())
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
instrumentation.startActivitySync(launchIntent);
instrumentation.waitForIdleSync();
return new AppLaunchInteractor();
}
@SuppressWarnings("unchecked") // Guarded by generics at the constructor.
private void launchActivity() {
if (activity != null) return;
Instrumentation instrumentation = fetchInstrumentation();
String targetPackage = instrumentation.getTargetContext().getPackageName();
Intent intent = getLaunchIntent(targetPackage, activityClass);
activity = (T) instrumentation.startActivitySync(intent);
instrumentation.waitForIdleSync();
}
/**
* Set the current item of the view pager to the requested position.
*
* @return the current item index after the action.
*/
private static int selectViewPagerItem(
Instrumentation instr, final HowItWorksActivity activity, final int position) {
TestUtilities.runOnMainSyncWithTimeout(
new Callable<Void>() {
@Override
public Void call() {
activity.setViewPagerCurrentItem(position);
return null;
}
});
instr.waitForIdleSync();
return activity.getViewPagerCurrentItem();
}
public static boolean clickView(Instrumentation instr, final View view) {
boolean result =
runOnMainSyncWithTimeout(
new Callable<Boolean>() {
@Override
public Boolean call() {
return view.performClick();
}
});
// this shouldn't be needed but without it or sleep, there isn't time for view refresh, etc.
instr.waitForIdleSync();
return result;
}
public static boolean longClickView(Instrumentation instr, final View view) {
boolean result =
runOnMainSyncWithTimeout(
new Callable<Boolean>() {
@Override
public Boolean call() {
return view.performLongClick();
}
});
instr.waitForIdleSync();
return result;
}
/** Sets the text of the provided {@link TextView} widget on the UI thread. */
public static void setText(Instrumentation instr, final TextView view, final String text) {
runOnMainSyncWithTimeout(
new Callable<Void>() {
@Override
public Void call() {
view.setText(text);
return null;
}
});
instr.waitForIdleSync();
Assert.assertEquals(text, view.getText().toString());
}
/**
* Opens the options menu of the provided {@link Activity} and invokes the menu item with the
* provided ID.
*
* <p>Note: This method cannot be invoked on the main thread.
*/
public static void openOptionsMenuAndInvokeItem(
Instrumentation instrumentation, final Activity activity, final int itemId) {
if (!instrumentation.invokeMenuActionSync(activity, itemId, 0)) {
throw new RuntimeException("Failed to invoke options menu item ID " + itemId);
}
instrumentation.waitForIdleSync();
}
public @NonNull InstrumentationLeakResults detectLeaks() {
Instrumentation instrumentation = getInstrumentation();
Context context = instrumentation.getTargetContext();
RefWatcher refWatcher = LeakCanary.installedRefWatcher();
Set<String> retainedKeys = refWatcher.getRetainedKeys();
if (refWatcher.isEmpty()) {
return InstrumentationLeakResults.NONE;
}
instrumentation.waitForIdleSync();
if (refWatcher.isEmpty()) {
return InstrumentationLeakResults.NONE;
}
GcTrigger.DEFAULT.runGc();
if (refWatcher.isEmpty()) {
return InstrumentationLeakResults.NONE;
}
// Waiting for any delayed UI post (e.g. scroll) to clear. This shouldn't be needed, but
// Android simply has way too many delayed posts that aren't canceled when views are detached.
SystemClock.sleep(2000);
if (refWatcher.isEmpty()) {
return InstrumentationLeakResults.NONE;
}
// Aaand we wait some more.
// 4 seconds (2+2) is greater than the 3 seconds delay for
// FINISH_TOKEN in android.widget.Filter
SystemClock.sleep(2000);
GcTrigger.DEFAULT.runGc();
if (refWatcher.isEmpty()) {
return InstrumentationLeakResults.NONE;
}
// We're always reusing the same file since we only execute this once at a time.
File heapDumpFile = new File(context.getFilesDir(), "instrumentation_tests_heapdump.hprof");
try {
Debug.dumpHprofData(heapDumpFile.getAbsolutePath());
} catch (Exception e) {
CanaryLog.d(e, "Could not dump heap");
return InstrumentationLeakResults.NONE;
}
HeapDump.Builder heapDumpBuilder = refWatcher.getHeapDumpBuilder();
HeapAnalyzer heapAnalyzer =
new HeapAnalyzer(heapDumpBuilder.excludedRefs, AnalyzerProgressListener.NONE,
heapDumpBuilder.reachabilityInspectorClasses);
List<TrackedReference> trackedReferences = heapAnalyzer.findTrackedReferences(heapDumpFile);
List<InstrumentationLeakResults.Result> detectedLeaks = new ArrayList<>();
List<InstrumentationLeakResults.Result> excludedLeaks = new ArrayList<>();
List<InstrumentationLeakResults.Result> failures = new ArrayList<>();
for (TrackedReference trackedReference : trackedReferences) {
// Ignore any Weak Reference that this test does not care about.
if (!retainedKeys.contains(trackedReference.key)) {
continue;
}
HeapDump heapDump = HeapDump.builder()
.heapDumpFile(heapDumpFile)
.referenceKey(trackedReference.key)
.referenceName(trackedReference.name)
.excludedRefs(heapDumpBuilder.excludedRefs)
.reachabilityInspectorClasses(heapDumpBuilder.reachabilityInspectorClasses)
.build();
AnalysisResult analysisResult =
heapAnalyzer.checkForLeak(heapDumpFile, trackedReference.key, false);
InstrumentationLeakResults.Result leakResult =
new InstrumentationLeakResults.Result(heapDump, analysisResult);
if (analysisResult.leakFound) {
if (!analysisResult.excludedLeak) {
detectedLeaks.add(leakResult);
} else {
excludedLeaks.add(leakResult);
}
} else if (analysisResult.failure != null) {
failures.add(leakResult);
}
}
CanaryLog.d("Found %d proper leaks, %d excluded leaks and %d leak analysis failures",
detectedLeaks.size(),
excludedLeaks.size(),
failures.size());
return new InstrumentationLeakResults(detectedLeaks, excludedLeaks, failures);
}
/**
* A setup for all end-to-end tests.
*
* @param inst the instrumentation
* @param activity the track list activity
*/
public static void setupForAllTest(Instrumentation inst, TrackListActivity activity) {
instrumentation = inst;
trackListActivity = activity;
SOLO = new Solo(instrumentation, trackListActivity);
if (!isGooglePlayServicesLatest) {
SOLO.finishOpenedActivities();
Assert.fail();
Log.e(TAG, "Need update Google Play Services");
}
// Check if open MyTracks first time after install. If so, there would be a
// welcome view with accept buttons. And makes sure only check once.
if (!isCheckedFirstLaunch) {
isGooglePlayServicesLatest = isGooglePlayServicesLatest();
if (!isGooglePlayServicesLatest) {
SOLO.finishOpenedActivities();
Assert.fail();
Log.e(TAG, "Need update Google Play Services");
}
setIsEmulator();
verifyFirstLaunch();
hasActionBar = setHasActionBar();
checkLanguage();
isCheckedFirstLaunch = true;
inst.waitForIdleSync();
// Check the status of real phone. For emulator, we would fix GPS signal.
if (!isEmulator) {
findAndClickMyLocation(activity);
hasGpsSignal = !SOLO.waitForText(NO_GPS_MESSAGE_PREFIX, 1, SHORT_WAIT_TIME);
SOLO.goBack();
}
}
int trackNumber = SOLO.getCurrentViews(ListView.class).get(0).getCount();
// Delete all tracks when there are two many tracks which may make some test
// run slowly, such as sync test cases.
if (trackNumber > 3) {
deleteAllTracks();
}
// Check whether is under recording. If previous test failed, the recording
// may not be recording.
if (isUnderRecording()) {
stopRecording(true);
}
resetAllSettings(activity, false);
inst.waitForIdleSync();
}