package de.dennisguse.opentracks.util; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isRoot; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.util.TreeIterables.breadthFirstViewTraversal; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.widget.ListView; import androidx.test.espresso.PerformException; import androidx.test.espresso.UiController; import androidx.test.espresso.ViewAction; import androidx.test.espresso.action.MotionEvents; import androidx.test.espresso.util.HumanReadables; import com.google.android.material.tabs.TabLayout; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import java.util.concurrent.TimeoutException; public class EspressoUtils { public static Matcher childAtPosition( final Matcher parentMatcher, final int position) { return new TypeSafeMatcher<>() { @Override public void describeTo(Description description) { description.appendText("Child at position " + position + " in parent "); parentMatcher.describeTo(description); } @Override public boolean matchesSafely(View view) { ViewParent parent = view.getParent(); return parent instanceof ViewGroup && parentMatcher.matches(parent) && view.equals(((ViewGroup) parent).getChildAt(position)); } }; } public static Matcher withListSize (final int size) { return new TypeSafeMatcher<>() { @Override public boolean matchesSafely(final View view) { return ((ListView) view).getCount() == size; } @Override public void describeTo(final Description description) { description.appendText("ListView should have " + size + " items"); } }; } public static ViewAction waitFor(final long duration_ms) { return new ViewAction() { @Override public String getDescription() { return "Wait for milliseconds."; } @Override public Matcher getConstraints() { return isDisplayed(); } @Override public void perform(UiController uiController, final View view) { uiController.loopMainThreadForAtLeast(duration_ms); } }; } public static ViewAction veryLongTouch(final int duration_ms) { return new ViewAction() { @Override public String getDescription() { return "Perform long touch."; } @Override public Matcher getConstraints() { return isDisplayed(); } @Override public void perform(UiController uiController, final View view) { // Get view absolute position int[] location = new int[2]; view.getLocationOnScreen(location); // Offset coordinates by view position float[] coordinates = new float[]{location[0] + 1, location[1] + 1}; // Send down event, pause, and send up MotionEvent down = MotionEvents.sendDown(uiController, coordinates, new float[]{1f, 1f}).down; uiController.loopMainThreadForAtLeast(duration_ms); MotionEvents.sendUp(uiController, down, coordinates); } }; } public static ViewAction waitId(final int viewId, final long millis) { return new ViewAction() { @Override public Matcher getConstraints() { return isRoot(); } @Override public String getDescription() { return "wait for a specific view with id <" + viewId + "> during " + millis + " millis."; } @Override public void perform(final UiController uiController, final View view) { uiController.loopMainThreadUntilIdle(); final long startTime = System.currentTimeMillis(); final long endTime = startTime + millis; final Matcher viewMatcher = withId(viewId); do { for (View child : breadthFirstViewTraversal(view)) { // found view with required ID if (viewMatcher.matches(child)) { return; } } uiController.loopMainThreadForAtLeast(50); } while (System.currentTimeMillis() < endTime); // timeout happens throw new PerformException.Builder() .withActionDescription(this.getDescription()) .withViewDescription(HumanReadables.describe(view)) .withCause(new TimeoutException()) .build(); } }; } public static ViewAction selectTabAtIndex(final int index) { return new ViewAction() { @Override public String getDescription() { return "Selecting tab."; } @Override public Matcher getConstraints() { return isDisplayed(); } @Override public void perform(UiController uiController, View view) { TabLayout tabLayout = (TabLayout) view; tabLayout.getTabAt(index).select(); } }; } }