Push Root Matcher into ViewInteraction and share it across the graph via an
AtomicReference. This way alt root selection works with out an minor api break
(changing the storage type)
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=58351508
diff --git a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java
index c66f178..3ff0da0 100644
--- a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java
+++ b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/Espresso.java
@@ -47,8 +47,8 @@
    * @param viewMatcher used to select the view.
    * @see #onData
    */
-  public static PartiallyScopedViewInteraction onView(final Matcher<View> viewMatcher) {
-    return new PartiallyScopedViewInteraction(viewMatcher);
+  public static ViewInteraction onView(final Matcher<View> viewMatcher) {
+    return espressoGraph().plus(new ViewInteractionModule(viewMatcher)).get(ViewInteraction.class);
   }
 
 
@@ -235,50 +235,5 @@
     }
   }
 
-  /**
-   * Represents a ViewInteraction which has not had a root matcher provided for it.
-   *
-   * By default Espresso uses a heuristic to choose the root window to operate on. Normally this
-   * is sufficient, however certain UX patterns may require the user to explicitly control which
-   * window Espresso operates upon.
-   *
-   * @see ViewInteraction
-   */
-  public static final class PartiallyScopedViewInteraction {
-    private final Matcher<View> viewMatcher;
-    private PartiallyScopedViewInteraction(Matcher<View> viewMatcher) {
-      this.viewMatcher = checkNotNull(viewMatcher);
-    }
 
-    /**
-     * Creates a ViewInteraction scoped to the root selected by the given root matcher.
-     */
-    public ViewInteraction inRoot(Matcher<Root> rootMatcher) {
-      checkNotNull(rootMatcher);
-      return espressoGraph().plus(new ViewInteractionModule(viewMatcher, rootMatcher))
-          .get(ViewInteraction.class);
-    }
-
-    /**
-     * Creates a ViewInteraction scoped to the the root selected by Espresso's heuristics
-     * and performs the given ViewActions.
-     *
-     * @see ViewInteraction#perform(ViewAction...)
-     */
-    public ViewInteraction perform(ViewAction... actions) {
-      return espressoGraph().plus(new ViewInteractionModule(viewMatcher))
-          .get(ViewInteraction.class).perform(actions);
-    }
-
-    /**
-     * Creates a ViewInteraction scoped to the the root selected by Espresso's heuristics
-     * and performs the given ViewAssertion.
-     *
-     * @see ViewInteraction#check(ViewAssertion)
-     */
-    public ViewInteraction check(ViewAssertion viewAssert) {
-      return espressoGraph().plus(new ViewInteractionModule(viewMatcher))
-          .get(ViewInteraction.class).check(viewAssert);
-    }
-  }
 }
diff --git a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java
index c6b13cf..a8a8d1d 100644
--- a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java
+++ b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteraction.java
@@ -19,6 +19,7 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.inject.Inject;
 
@@ -40,6 +41,7 @@
   private final Executor mainThreadExecutor;
   private final FailureHandler failureHandler;
   private final Matcher<View> viewMatcher;
+  private final AtomicReference<Matcher<Root>> rootMatcherRef;
 
   @Inject
   ViewInteraction(
@@ -47,12 +49,14 @@
       ViewFinder viewFinder,
       @MainThread Executor mainThreadExecutor,
       FailureHandler failureHandler,
-      Matcher<View> viewMatcher) {
+      Matcher<View> viewMatcher,
+      AtomicReference<Matcher<Root>> rootMatcherRef) {
     this.viewFinder = checkNotNull(viewFinder);
     this.uiController = checkNotNull(uiController);
     this.failureHandler = checkNotNull(failureHandler);
     this.mainThreadExecutor = checkNotNull(mainThreadExecutor);
     this.viewMatcher = checkNotNull(viewMatcher);
+    this.rootMatcherRef = checkNotNull(rootMatcherRef);
   }
 
   /**
@@ -71,6 +75,15 @@
     return this;
   }
 
+
+  /**
+   * Makes this ViewInteraction scoped to the root selected by the given root matcher.
+   */
+  public ViewInteraction inRoot(Matcher<Root> rootMatcher) {
+    this.rootMatcherRef.set(checkNotNull(rootMatcher));
+    return this;
+  }
+
   private void doPerform(final ViewAction viewAction) {
     checkNotNull(viewAction);
     final Matcher<? extends View> constraints = checkNotNull(viewAction.getConstraints());
diff --git a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java
index fbdc0ea..d94ecef 100644
--- a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java
+++ b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionModule.java
@@ -12,6 +12,7 @@
 import dagger.Provides;
 
 import org.hamcrest.Matcher;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Adds the user interaction scope to the Espresso graph.
@@ -22,19 +23,15 @@
 class ViewInteractionModule {
 
   private final Matcher<View> viewMatcher;
-  private final Matcher<Root> rootMatcher;
+  private final AtomicReference<Matcher<Root>> rootMatcher =
+      new AtomicReference<Matcher<Root>>(RootMatchers.DEFAULT);
 
   ViewInteractionModule(Matcher<View> viewMatcher) {
-    this(viewMatcher, RootMatchers.DEFAULT);
-  }
-
-  ViewInteractionModule(Matcher<View> viewMatcher, Matcher<Root> rootMatcher) {
     this.viewMatcher = checkNotNull(viewMatcher);
-    this.rootMatcher = checkNotNull(rootMatcher);
   }
 
   @Provides
-  Matcher<Root> provideRootMatcher() {
+  AtomicReference<Matcher<Root>> provideRootMatcher() {
     return rootMatcher;
   }
 
diff --git a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java
index 8222973..087cd4a 100644
--- a/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java
+++ b/espresso/lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/RootViewPicker.java
@@ -24,6 +24,7 @@
 import java.util.EnumSet;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
@@ -42,22 +43,24 @@
   private final Provider<List<Root>> rootsOracle;
   private final UiController uiController;
   private final ActivityLifecycleMonitor activityLifecycleMonitor;
-  private final Matcher<Root> rootMatcher;
+  private final AtomicReference<Matcher<Root>> rootMatcherRef;
 
   private List<Root> roots;
 
   @Inject
   RootViewPicker(Provider<List<Root>> rootsOracle, UiController uiController,
-      ActivityLifecycleMonitor activityLifecycleMonitor, Matcher<Root> rootMatcher) {
+      ActivityLifecycleMonitor activityLifecycleMonitor,
+      AtomicReference<Matcher<Root>> rootMatcherRef) {
     this.rootsOracle = rootsOracle;
     this.uiController = uiController;
     this.activityLifecycleMonitor = activityLifecycleMonitor;
-    this.rootMatcher = rootMatcher;
+    this.rootMatcherRef = rootMatcherRef;
   }
 
   @Override
   public View get() {
     checkState(Looper.getMainLooper().equals(Looper.myLooper()), "must be called on main thread.");
+    Matcher<Root> rootMatcher = rootMatcherRef.get();
 
     Root root = findRoot(rootMatcher);
 
diff --git a/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java b/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java
index 1333fc1..4a2d896 100644
--- a/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java
+++ b/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/ViewInteractionTest.java
@@ -4,6 +4,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -11,6 +12,7 @@
 
 import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitor;
 import com.google.android.apps.common.testing.testrunner.ActivityLifecycleMonitorRegistry;
+import com.google.android.apps.common.testing.ui.espresso.matcher.RootMatchers;
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.MoreExecutors;
 
@@ -22,6 +24,7 @@
 import org.mockito.Mock;
 
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
 
 /** Unit tests for {@link ViewInteraction}. */
 public class ViewInteractionTest extends AndroidTestCase {
@@ -44,6 +47,7 @@
   private View targetView;
   private Matcher<View> viewMatcher;
   private Matcher<View> actionConstraint;
+  private AtomicReference<Matcher<Root>> rootMatcherRef;
 
   @Override
   public void setUp() throws Exception {
@@ -54,6 +58,7 @@
     targetView = new View(getContext());
     viewMatcher = is(targetView);
     actionConstraint = Matchers.<View>notNullValue();
+    rootMatcherRef = new AtomicReference<Matcher<Root>>(RootMatchers.DEFAULT);
     when(mockAction.getDescription()).thenReturn("A Mock!");
     failureHandler = new FailureHandler() {
       @Override
@@ -154,6 +159,22 @@
           Optional.<NoMatchingViewException>absent());
   }
 
+  public void testInRootUpdatesRef() {
+    initInteraction();
+    Matcher<Root> testMatcher = nullValue();
+    testInteraction.inRoot(testMatcher);
+    assertEquals(testMatcher, rootMatcherRef.get());
+  }
+
+  public void testInRoot_NullHandling() {
+    initInteraction();
+    try {
+      testInteraction.inRoot(null);
+      fail("should throw");
+    } catch (NullPointerException expected) {
+    }
+  }
+
   public void testCheck_ViewCannotBeFound() {
     NoMatchingViewException noViewException = new NoMatchingViewException.Builder()
         .withViewMatcher(viewMatcher)
@@ -170,7 +191,7 @@
     when(mockAction.getConstraints()).thenReturn(actionConstraint);
 
     testInteraction = new ViewInteraction(mockUiController, mockViewFinder, testExecutor,
-        failureHandler, viewMatcher);
+        failureHandler, viewMatcher, rootMatcherRef);
 
   }
 }
diff --git a/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/sample/MultipleWindowTest.java b/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/sample/MultipleWindowTest.java
index 28d2688..ecdb65d 100644
--- a/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/sample/MultipleWindowTest.java
+++ b/espresso/libtests/src/main/java/com/google/android/apps/common/testing/ui/espresso/sample/MultipleWindowTest.java
@@ -19,6 +19,7 @@
 import com.google.android.apps.common.testing.ui.testapp.R;
 import com.google.android.apps.common.testing.ui.testapp.SendActivity;
 
+import android.os.Build;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 
@@ -48,6 +49,10 @@
   }
 
   public void testInteractionsWithAutoCompletePopup() {
+    if (Build.VERSION.SDK_INT < 10) {
+      // Froyo's AutoCompleteTextBox is broken - do not bother testing with it.
+      return;
+    }
     // Android's Window system allows multiple view hierarchies to layer on top of each other.
     //
     // A real world analogy would be an overhead projector with multiple transparencies placed