package com.mindbodyonline.ironhide.Infrastructure.Extensions; import android.app.Activity; import android.os.Looper; import android.support.test.espresso.AmbiguousViewMatcherException; import android.support.test.espresso.NoMatchingViewException; import android.support.test.espresso.ViewFinder; import android.view.View; import com.android.support.test.deps.guava.base.Predicate; import com.android.support.test.deps.guava.collect.Iterables; import com.android.support.test.deps.guava.collect.Iterators; import org.hamcrest.Matcher; import java.util.Iterator; import static android.support.test.espresso.util.TreeIterables.breadthFirstViewTraversal; import static com.android.support.test.deps.guava.base.Preconditions.checkNotNull; import static com.android.support.test.deps.guava.base.Preconditions.checkState; /** * Adapted from {@link android.support.test.espresso.base.ViewFinderImpl}. * Searches the given activity for the {@link View} matching the supplied {@link Matcher} */ public class ActivityViewFinder implements ViewFinder { private View root; private Matcher<View> viewMatcher; public ActivityViewFinder(Activity from, Matcher<View> viewMatcher) { root = from.getWindow().findViewById(android.R.id.content); this.viewMatcher = viewMatcher; } /** {@inheritDoc} */ @Override public View getView() throws AmbiguousViewMatcherException, NoMatchingViewException { checkMainThread(); final Predicate<View> matcherPredicate = new MatcherPredicateAdapter<>( checkNotNull(viewMatcher)); Iterator<View> matchedViewIterator = Iterables.filter( breadthFirstViewTraversal(root), matcherPredicate).iterator(); View matchedView = null; while (matchedViewIterator.hasNext()) { if (matchedView != null) { // Ambiguous! throw new AmbiguousViewMatcherException.Builder() .includeViewHierarchy(false) .withViewMatcher(viewMatcher) .withRootView(root) .withView1(matchedView) .withView2(matchedViewIterator.next()) .withOtherAmbiguousViews(Iterators.toArray(matchedViewIterator, View.class)) .build(); } else matchedView = matchedViewIterator.next(); } // no need to throw NoMatchingViewExceptions. We want the null value if view does not exist return matchedView; } /** @see android.support.test.espresso.base.ViewFinderImpl#checkMainThread() */ private void checkMainThread() { checkState(Thread.currentThread().equals(Looper.getMainLooper().getThread()), "Executing a query on the view hierarchy outside of the main thread (on: %s)", Thread.currentThread().getName()); } private static class MatcherPredicateAdapter<T> implements Predicate<T> { private final Matcher<? super T> matcher; private MatcherPredicateAdapter(Matcher<? super T> matcher) { this.matcher = checkNotNull(matcher); } @Override public boolean apply(T input) { return matcher.matches(input); } } }