DO NOT MERGE - Moar Autofill CTS improvements:

- Created a MultipleExceptionsCatcher used to throw multiple exceptions.
- Ignore fillRequests() when the service is not enabled.
- Created a custom ActivityTestRule that cleans up autofill state before
  starting the activity.
- Moved some helpers from AutoFillServiceTestCase to Helper.

Test: CtsAutoFillServiceTestCases pass
Test: AutoFinishSessionTest doesn't fail anymore when started after a previous failed test

Bug: 37566627
Fixes: 62717612

Change-Id: Ia6016267b07dfeaf1fc5e349dfa7f12e31f1f27b
Merged-In: Ia6016267b07dfeaf1fc5e349dfa7f12e31f1f27b
(cherry picked from commit b8b8363684c8a2d5ad02c7e36bd6bba6e6dc2f00)
diff --git a/tests/autofillservice/Android.mk b/tests/autofillservice/Android.mk
index f4437f7..27a8cb5 100644
--- a/tests/autofillservice/Android.mk
+++ b/tests/autofillservice/Android.mk
@@ -23,6 +23,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-annotations \
     compatibility-device-util \
     ctstestrunner \
     truth-prebuilt \
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index 15d1052..209b043 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -16,16 +16,17 @@
 
 package android.autofillservice.cts;
 
+import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.Helper.getLoggingLevel;
 import static android.autofillservice.cts.Helper.hasAutofillFeature;
 import static android.autofillservice.cts.Helper.runShellCommand;
 import static android.autofillservice.cts.Helper.setLoggingLevel;
+import static android.autofillservice.cts.InstrumentedAutoFillService.SERVICE_NAME;
 import static android.provider.Settings.Secure.AUTOFILL_SERVICE;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.autofillservice.cts.InstrumentedAutoFillService.Replier;
-import android.content.Context;
 import android.content.pm.PackageManager;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
@@ -39,6 +40,8 @@
 import org.junit.Rule;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
 /**
  * Base class for all other tests.
  */
@@ -46,10 +49,6 @@
 abstract class AutoFillServiceTestCase {
     private static final String TAG = "AutoFillServiceTestCase";
 
-    private static final String SERVICE_NAME =
-            InstrumentedAutoFillService.class.getPackage().getName()
-            + "/." + InstrumentedAutoFillService.class.getSimpleName();
-
     protected static UiBot sUiBot;
 
     protected static final Replier sReplier = InstrumentedAutoFillService.getReplier();
@@ -82,30 +81,16 @@
 
     @AfterClass
     public static void resetSettings() {
-        runShellCommand("settings delete secure %s", AUTOFILL_SERVICE);
-    }
-
-    @Before
-    public void disableService() {
         if (!hasAutofillFeature()) return;
 
-        if (!isServiceEnabled()) return;
-
-        final OneTimeSettingsListener observer = new OneTimeSettingsListener(getContext(),
-                AUTOFILL_SERVICE);
+        // Clean up only - no need to call disableService() because it doesn't need to fail if
+        // it's not reset.
         runShellCommand("settings delete secure %s", AUTOFILL_SERVICE);
-        observer.assertCalled();
-        assertServiceDisabled();
-
-        InstrumentedAutoFillService.setIgnoreUnexpectedRequests(false);
     }
 
     @Before
     public void reset() {
-        destroyAllSessions();
         sReplier.reset();
-        InstrumentedAutoFillService.resetStaticState();
-        AuthenticationActivity.resetStaticState();
     }
 
     @Before
@@ -136,9 +121,18 @@
     // exceptions would mask the real cause. A better approach might be using a @Rule or some other
     // visitor pattern.
     @After
-    public void assertNoPendingRequests() {
-        sReplier.assertNumberUnhandledFillRequests(0);
-        sReplier.assertNumberUnhandledSaveRequests(0);
+    public void assertNothingIsPending() throws Exception {
+        final MultipleExceptionsCatcher catcher = new MultipleExceptionsCatcher()
+            .run(() -> sReplier.assertNumberUnhandledFillRequests(0))
+            .run(() -> sReplier.assertNumberUnhandledSaveRequests(0));
+
+        final List<Exception> replierExceptions = sReplier.getExceptions();
+        if (replierExceptions != null) {
+            for (Exception e : replierExceptions) {
+                catcher.add(e);
+            }
+        }
+        catcher.throwIfAny();
     }
 
     @After
@@ -150,13 +144,18 @@
      * Enables the {@link InstrumentedAutoFillService} for autofill for the current user.
      */
     protected void enableService() {
-        if (isServiceEnabled()) return;
+        Helper.enableAutofillService(getContext(), SERVICE_NAME);
+        InstrumentedAutoFillService.setIgnoreUnexpectedRequests(false);
+    }
 
-        final OneTimeSettingsListener observer = new OneTimeSettingsListener(getContext(),
-                AUTOFILL_SERVICE);
-        runShellCommand("settings put secure %s %s default", AUTOFILL_SERVICE, SERVICE_NAME);
-        observer.assertCalled();
-        assertServiceEnabled();
+    /**
+     * Disables the {@link InstrumentedAutoFillService} for autofill for the current user.
+     */
+    protected void disableService() {
+        if (!hasAutofillFeature()) return;
+
+        Helper.disableAutofillService(getContext(), SERVICE_NAME);
+        InstrumentedAutoFillService.setIgnoreUnexpectedRequests(true);
     }
 
     /**
@@ -182,19 +181,7 @@
         assertWithMessage("Dangling sessions ('%s'): %s'", command, result).that(result).isEmpty();
     }
 
-    /**
-     * Destroys all sessions.
-     */
-    protected void destroyAllSessions() {
-        runShellCommand("cmd autofill destroy sessions");
-        assertNoDanglingSessions();
-    }
-
-    protected static Context getContext() {
-        return InstrumentationRegistry.getInstrumentation().getContext();
-    }
-
-    protected static RemoteViews createPresentation(String message) {
+    protected RemoteViews createPresentation(String message) {
         final RemoteViews presentation = new RemoteViews(getContext()
                 .getPackageName(), R.layout.list_item);
         presentation.setTextViewText(R.id.text1, message);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
index ab1c0ea..b966078 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
@@ -18,6 +18,7 @@
 
 import static android.autofillservice.cts.FragmentContainerActivity.FRAGMENT_TAG;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -28,7 +29,6 @@
 import android.service.autofill.SaveInfo;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.test.rule.ActivityTestRule;
 import android.view.ViewGroup;
 import android.widget.EditText;
 
@@ -41,8 +41,8 @@
  */
 public class AutoFinishSessionTest extends AutoFillServiceTestCase {
     @Rule
-    public final ActivityTestRule<FragmentContainerActivity> mActivityRule =
-            new ActivityTestRule<>(FragmentContainerActivity.class);
+    public final AutofillActivityTestRule<FragmentContainerActivity> mActivityRule =
+            new AutofillActivityTestRule<>(FragmentContainerActivity.class);
     private FragmentContainerActivity mActivity;
     private EditText mEditText1;
     private EditText mEditText2;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java
new file mode 100644
index 0000000..7cf3c64
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillActivityTestRule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.autofillservice.cts;
+
+import android.app.Activity;
+import android.support.test.rule.ActivityTestRule;
+
+/**
+ * Custom {@link ActivityTestRule} that cleans up the autofill state before the activity is
+ * launched.
+ */
+public class AutofillActivityTestRule<T extends Activity> extends ActivityTestRule<T> {
+
+    public AutofillActivityTestRule(Class<T> activityClass) {
+        super(activityClass);
+    }
+
+    @Override
+    protected void beforeActivityLaunched() {
+        Helper.preTestCleanup();
+
+        super.beforeActivityLaunched();
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
index 0ed3c86..ff18003 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
@@ -26,7 +26,6 @@
 import android.icu.util.Calendar;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.test.rule.ActivityTestRule;
 import android.view.View;
 import android.view.autofill.AutofillValue;
 import android.widget.CompoundButton;
@@ -57,8 +56,8 @@
  */
 public class AutofillValueTest extends AutoFillServiceTestCase {
     @Rule
-    public final ActivityTestRule<AllAutofillableViewsActivity> mActivityRule =
-            new ActivityTestRule<>(AllAutofillableViewsActivity.class);
+    public final AutofillActivityTestRule<AllAutofillableViewsActivity> mActivityRule =
+            new AutofillActivityTestRule<>(AllAutofillableViewsActivity.class);
 
     private AllAutofillableViewsActivity mActivity;
     private EditText mEditText;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
index c3809a0..6ba5431 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
@@ -31,6 +31,7 @@
 import static android.autofillservice.cts.Helper.assertToggleIsSanitized;
 import static android.autofillservice.cts.Helper.assertToggleValue;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
 import static android.view.View.AUTOFILL_TYPE_LIST;
 
@@ -41,7 +42,6 @@
 import android.autofillservice.cts.CannedFillResponse.CannedDataset;
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.support.test.rule.ActivityTestRule;
 import android.widget.ArrayAdapter;
 import android.widget.Spinner;
 
@@ -58,8 +58,8 @@
 public class CheckoutActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<CheckoutActivity> mActivityRule =
-        new ActivityTestRule<CheckoutActivity>(CheckoutActivity.class);
+    public final AutofillActivityTestRule<CheckoutActivity> mActivityRule =
+        new AutofillActivityTestRule<CheckoutActivity>(CheckoutActivity.class);
 
     private CheckoutActivity mActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
index a51a00c..40c11d3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatePickerCalendarActivityTest.java
@@ -15,15 +15,13 @@
  */
 package android.autofillservice.cts;
 
-import android.support.test.rule.ActivityTestRule;
-
 import org.junit.Rule;
 
 public class DatePickerCalendarActivityTest extends DatePickerTestCase<DatePickerCalendarActivity> {
 
     @Rule
-    public final ActivityTestRule<DatePickerCalendarActivity> mActivityRule =
-        new ActivityTestRule<DatePickerCalendarActivity>(DatePickerCalendarActivity.class);
+    public final AutofillActivityTestRule<DatePickerCalendarActivity> mActivityRule =
+        new AutofillActivityTestRule<DatePickerCalendarActivity>(DatePickerCalendarActivity.class);
 
     @Override
     protected DatePickerCalendarActivity getDatePickerActivity() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
index 10851cd..0497f87 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatePickerSpinnerActivityTest.java
@@ -15,15 +15,13 @@
  */
 package android.autofillservice.cts;
 
-import android.support.test.rule.ActivityTestRule;
-
 import org.junit.Rule;
 
 public class DatePickerSpinnerActivityTest extends DatePickerTestCase<DatePickerSpinnerActivity> {
 
     @Rule
-    public final ActivityTestRule<DatePickerSpinnerActivity> mActivityRule =
-        new ActivityTestRule<DatePickerSpinnerActivity>(DatePickerSpinnerActivity.class);
+    public final AutofillActivityTestRule<DatePickerSpinnerActivity> mActivityRule =
+        new AutofillActivityTestRule<DatePickerSpinnerActivity>(DatePickerSpinnerActivity.class);
 
     @Override
     protected DatePickerSpinnerActivity getDatePickerActivity() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java
index a2edf4d..b2dd1d4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FatActivityTest.java
@@ -18,18 +18,18 @@
 import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
 import static android.autofillservice.cts.FatActivity.ID_CAPTCHA;
 import static android.autofillservice.cts.FatActivity.ID_IMAGE;
-import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_IMAGE;
-import static android.autofillservice.cts.FatActivity.ID_INPUT;
-import static android.autofillservice.cts.FatActivity.ID_INPUT_CONTAINER;
 import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS;
 import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_CHILD;
 import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_GRAND_CHILD;
-import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS;
-import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_CHILD;
-import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_GRAND_CHILD;
+import static android.autofillservice.cts.FatActivity.ID_IMPORTANT_IMAGE;
+import static android.autofillservice.cts.FatActivity.ID_INPUT;
+import static android.autofillservice.cts.FatActivity.ID_INPUT_CONTAINER;
 import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS;
 import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_CHILD;
 import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_EXCLUDING_DESCENDANTS_GRAND_CHILD;
+import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS;
+import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_CHILD;
+import static android.autofillservice.cts.FatActivity.ID_NOT_IMPORTANT_CONTAINER_MIXED_DESCENDANTS_GRAND_CHILD;
 import static android.autofillservice.cts.Helper.assertNumberOfChildren;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
 import static android.autofillservice.cts.Helper.findNodeByText;
@@ -38,7 +38,6 @@
 
 import android.app.assist.AssistStructure.ViewNode;
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
-import android.support.test.rule.ActivityTestRule;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -50,8 +49,8 @@
 public class FatActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<FatActivity> mActivityRule =
-        new ActivityTestRule<FatActivity>(FatActivity.class);
+    public final AutofillActivityTestRule<FatActivity> mActivityRule =
+        new AutofillActivityTestRule<FatActivity>(FatActivity.class);
 
     private FatActivity mFatActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index cf383a1..7c91578 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -17,6 +17,7 @@
 package android.autofillservice.cts;
 
 import static android.autofillservice.cts.Helper.runShellCommand;
+import static android.autofillservice.cts.InstrumentedAutoFillService.SERVICE_NAME;
 import static android.provider.Settings.Secure.AUTOFILL_SERVICE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -696,6 +697,92 @@
         runShellCommand("cmd autofill set log_level %s", level);
     }
 
+    /**
+     * Uses Settings to enable the given autofill service for the default user, and checks the
+     * value was properly check, throwing an exception if it was not.
+     */
+    public static void enableAutofillService(Context context, String serviceName) {
+        if (isAutofillServiceEnabled(serviceName)) return;
+
+        final OneTimeSettingsListener observer = new OneTimeSettingsListener(context,
+                AUTOFILL_SERVICE);
+        runShellCommand("settings put secure %s %s default", AUTOFILL_SERVICE, serviceName);
+        observer.assertCalled();
+        assertAutofillServiceStatus(serviceName, true);
+    }
+
+    /**
+     * Uses Settings to disable the given autofill service for the default user, and checks the
+     * value was properly check, throwing an exception if it was not.
+     */
+    public static void disableAutofillService(Context context, String serviceName) {
+        if (!isAutofillServiceEnabled(serviceName)) return;
+
+        final OneTimeSettingsListener observer = new OneTimeSettingsListener(context,
+                AUTOFILL_SERVICE);
+        runShellCommand("settings delete secure %s", AUTOFILL_SERVICE);
+        observer.assertCalled();
+        assertAutofillServiceStatus(serviceName, false);
+    }
+
+    /**
+     * Checks whether the given service is set as the autofill service for the default user.
+     */
+    public static boolean isAutofillServiceEnabled(String serviceName) {
+        final String actualName = runShellCommand("settings get secure %s", AUTOFILL_SERVICE);
+        return serviceName.equals(actualName);
+    }
+
+    /**
+     * Asserts whether the given service is enabled as the autofill service for the default user.
+     */
+    public static void assertAutofillServiceStatus(String serviceName, boolean enabled) {
+        final String actual = runShellCommand("settings get secure %s", AUTOFILL_SERVICE);
+        final String expected = enabled ? serviceName : "null";
+        assertWithMessage("Invalid value for secure setting %s", AUTOFILL_SERVICE)
+                .that(actual).isEqualTo(expected);
+    }
+
+    /**
+     * Asserts that there is no session left in the service.
+     */
+    public static void assertNoDanglingSessions() {
+        final String command = "cmd autofill list sessions";
+        final String result = runShellCommand(command);
+        assertWithMessage("Dangling sessions ('%s'): %s'", command, result).that(result).isEmpty();
+    }
+
+    /**
+     * Destroys all sessions.
+     */
+    public static void destroyAllSessions() {
+        runShellCommand("cmd autofill destroy sessions");
+        assertNoDanglingSessions();
+    }
+
+    /**
+     * Gets the instrumentation context.
+     */
+    public static Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+
+    /**
+     * Cleans up the autofill state; should be called before pretty much any test.
+     */
+    public static void preTestCleanup() {
+        if (!hasAutofillFeature()) return;
+
+        Log.d(TAG, "preTestCleanup()");
+
+        disableAutofillService(getContext(), SERVICE_NAME);
+        InstrumentedAutoFillService.setIgnoreUnexpectedRequests(true);
+
+        destroyAllSessions();
+        InstrumentedAutoFillService.resetStaticState();
+        AuthenticationActivity.resetStaticState();
+    }
+
     private Helper() {
     }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
index cfdb6e4..07c67eb9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InitializedCheckoutActivityTest.java
@@ -28,7 +28,6 @@
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
 
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
-import android.support.test.rule.ActivityTestRule;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -40,8 +39,8 @@
 public class InitializedCheckoutActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<InitializedCheckoutActivity> mActivityRule =
-        new ActivityTestRule<InitializedCheckoutActivity>(InitializedCheckoutActivity.class);
+    public final AutofillActivityTestRule<InitializedCheckoutActivity> mActivityRule =
+        new AutofillActivityTestRule<InitializedCheckoutActivity>(InitializedCheckoutActivity.class);
 
     private InitializedCheckoutActivity mCheckoutActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
index 81e3387..12fec5a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
@@ -38,8 +38,10 @@
 import android.service.autofill.FillContext;
 import android.service.autofill.FillResponse;
 import android.service.autofill.SaveCallback;
+import android.support.annotation.Nullable;
 import android.util.Log;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -51,6 +53,9 @@
  */
 public class InstrumentedAutoFillService extends AutofillService {
 
+    static final String SERVICE_NAME = InstrumentedAutoFillService.class.getPackage()
+            .getName() + "/." + InstrumentedAutoFillService.class.getSimpleName();
+
     private static final String TAG = "InstrumentedAutoFillService";
 
     private static final boolean DUMP_FILL_REQUESTS = false;
@@ -64,6 +69,9 @@
     private static final Replier sReplier = new Replier();
     private static final BlockingQueue<String> sConnectionStates = new LinkedBlockingQueue<>();
 
+    private static final Object sLock = new Object();
+
+    // @GuardedBy("sLock")
     private static boolean sIgnoreUnexpectedRequests = false;
 
     public InstrumentedAutoFillService() {
@@ -89,9 +97,11 @@
     @Override
     public void onFillRequest(android.service.autofill.FillRequest request,
             CancellationSignal cancellationSignal, FillCallback callback) {
-        if (sIgnoreUnexpectedRequests || !fromSamePackage(request.getFillContexts()))  {
-            Log.w(TAG, "Ignoring onFillRequest()");
-            return;
+        synchronized (sLock) {
+            if (sIgnoreUnexpectedRequests || !fromSamePackage(request.getFillContexts()))  {
+                Log.w(TAG, "Ignoring onFillRequest()");
+                return;
+            }
         }
         if (DUMP_FILL_REQUESTS) dumpStructure("onFillRequest()", request.getFillContexts());
         sReplier.onFillRequest(request.getFillContexts(), request.getClientState(),
@@ -101,9 +111,11 @@
     @Override
     public void onSaveRequest(android.service.autofill.SaveRequest request,
             SaveCallback callback) {
-        if (sIgnoreUnexpectedRequests || !fromSamePackage(request.getFillContexts())) {
-            Log.w(TAG, "Ignoring onSaveRequest()");
-            return;
+        synchronized (sLock) {
+            if (sIgnoreUnexpectedRequests || !fromSamePackage(request.getFillContexts())) {
+                Log.w(TAG, "Ignoring onSaveRequest()");
+                return;
+            }
         }
         if (DUMP_SAVE_REQUESTS) dumpStructure("onSaveRequest()", request.getFillContexts());
         sReplier.onSaveRequest(request.getFillContexts(), request.getClientState(), callback);
@@ -126,7 +138,9 @@
      * should throw an exception.
      */
     public static void setIgnoreUnexpectedRequests(boolean ignore) {
-        sIgnoreUnexpectedRequests = ignore;
+        synchronized (sLock) {
+            sIgnoreUnexpectedRequests = ignore;
+        }
     }
 
     /**
@@ -231,10 +245,28 @@
         private final BlockingQueue<FillRequest> mFillRequests = new LinkedBlockingQueue<>();
         private final BlockingQueue<SaveRequest> mSaveRequests = new LinkedBlockingQueue<>();
 
+        private List<Exception> mExceptions;
+
         private Replier() {
         }
 
         /**
+         * Gets the exceptions thrown asynchronously, if any.
+         */
+        @Nullable List<Exception> getExceptions() {
+            return mExceptions;
+        }
+
+        private void addException(@Nullable Exception e) {
+            if (e == null) return;
+
+            if (mExceptions == null) {
+                mExceptions = new ArrayList<>();
+            }
+            mExceptions.add(e);
+        }
+
+        /**
          * Sets the expectation for the next {@code onFillRequest} as {@link FillResponse} with just
          * one {@link Dataset}.
          */
@@ -280,6 +312,13 @@
         }
 
         /**
+         * Gets the current number of unhandled requests.
+         */
+        int getNumberUnhandledFillRequests() {
+            return mFillRequests.size();
+        }
+
+        /**
          * Gets the next save request, in the order received.
          *
          * <p>Typically called at the end of a test case, to assert the initial request.
@@ -310,6 +349,7 @@
             mResponses.clear();
             mFillRequests.clear();
             mSaveRequests.clear();
+            mExceptions = null;
         }
 
         private void onFillRequest(List<FillContext> contexts, Bundle data,
@@ -321,11 +361,14 @@
                 } catch (InterruptedException e) {
                     Log.w(TAG, "Interrupted getting CannedResponse: " + e);
                     Thread.currentThread().interrupt();
+                    addException(e);
                     return;
                 }
                 if (response == null) {
-                    dumpStructure("onFillRequest() without response", contexts);
-                    throw new RetryableException("No CannedResponse");
+                    final String msg = "onFillRequest() received when no CannedResponse was set";
+                    dumpStructure(msg, contexts);
+                    addException(new RetryableException(msg));
+                    return;
                 }
                 if (response.getResponseType() == NULL) {
                     Log.d(TAG, "onFillRequest(): replying with null");
@@ -350,6 +393,8 @@
 
                 Log.v(TAG, "onFillRequest(): fillResponse = " + fillResponse);
                 callback.onSuccess(fillResponse);
+            } catch (Exception e) {
+                addException(e);
             } finally {
                 mFillRequests.offer(new FillRequest(contexts, data, cancellationSignal, callback,
                         flags));
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 686a056..72f5197 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -18,12 +18,13 @@
 
 import static android.app.Activity.RESULT_CANCELED;
 import static android.app.Activity.RESULT_OK;
+import static android.autofillservice.cts.CannedFillResponse.DO_NOT_REPLY_RESPONSE;
 import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
 import static android.autofillservice.cts.CheckoutActivity.ID_CC_NUMBER;
-import static android.autofillservice.cts.CannedFillResponse.DO_NOT_REPLY_RESPONSE;
 import static android.autofillservice.cts.Helper.ID_PASSWORD;
 import static android.autofillservice.cts.Helper.ID_PASSWORD_LABEL;
 import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.assertNoDanglingSessions;
 import static android.autofillservice.cts.Helper.assertNumberOfChildren;
 import static android.autofillservice.cts.Helper.assertTextAndValue;
 import static android.autofillservice.cts.Helper.assertTextIsSanitized;
@@ -31,6 +32,7 @@
 import static android.autofillservice.cts.Helper.dumpStructure;
 import static android.autofillservice.cts.Helper.eventually;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.Helper.runShellCommand;
 import static android.autofillservice.cts.Helper.setUserComplete;
 import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilConnected;
@@ -72,7 +74,6 @@
 import android.service.autofill.FillEventHistory;
 import android.service.autofill.FillResponse;
 import android.service.autofill.SaveInfo;
-import android.support.test.rule.ActivityTestRule;
 import android.support.test.uiautomator.UiObject2;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
@@ -99,8 +100,8 @@
 public class LoginActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<LoginActivity> mActivityRule = new ActivityTestRule<LoginActivity>(
-            LoginActivity.class);
+    public final AutofillActivityTestRule<LoginActivity> mActivityRule =
+        new AutofillActivityTestRule<LoginActivity>(LoginActivity.class);
 
     private LoginActivity mActivity;
 
@@ -1172,7 +1173,7 @@
             throw e;
         }
 
-        // Sanity check: once saved, the session should be finsihed.
+        // Sanity check: once saved, the session should be finished.
         assertNoDanglingSessions();
     }
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultipleExceptionsCatcher.java b/tests/autofillservice/src/android/autofillservice/cts/MultipleExceptionsCatcher.java
new file mode 100644
index 0000000..3750c30
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultipleExceptionsCatcher.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper used to catch multiple exceptions that might have happened in a test case.
+ */
+// TODO: move to common CTS code (and add test cases to it)
+public final class MultipleExceptionsCatcher {
+
+    private static final String TAG = "MultipleExceptionsCatcher";
+
+    private final List<Throwable> mThrowables = new ArrayList<>();
+
+    /**
+     * Runs {@code r} postponing any thrown exception to {@link #throwIfAny()}.
+     */
+    public MultipleExceptionsCatcher run(@NonNull Runnable r) {
+        try {
+            r.run();
+        } catch (Throwable t) {
+            mThrowables.add(t);
+        }
+        return this;
+    }
+
+    /**
+     * Adds an exception - if it's not {@code null} to the exceptions thrown by
+     * {@link #throwIfAny()}.
+     */
+    public MultipleExceptionsCatcher add(@Nullable Throwable t) {
+        if (t != null) {
+            mThrowables.add(t);
+        }
+        return this;
+    }
+
+    /**
+     * Throws one exception merging all exceptions thrown or added so far, if any.
+     */
+    public void throwIfAny() throws Exception {
+        if (mThrowables.isEmpty()) return;
+
+        if (mThrowables.size() == 1) {
+            final Throwable t = mThrowables.get(0);
+            if (t instanceof Exception) {
+                throw (Exception) t;
+            }
+        }
+
+        String msg = "D'OH!";
+        try {
+            try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
+                sw.write("Caught " + mThrowables.size() + " exceptions\n");
+                for (int i = 0; i < mThrowables.size(); i++) {
+                    sw.write("\n---- Begin of exception #" + (i + 1) + " ----\n");
+                    final Throwable exception = mThrowables.get(i);
+                    exception.printStackTrace(pw);
+                    sw.write("---- End of exception #" + (i + 1) + " ----\n\n");
+                }
+                msg = sw.toString();
+            }
+        } catch (IOException e) {
+            // ignore close() errors - should not happen...
+            Log.e(TAG, "Exception closing StringWriter: " + e);
+        }
+        throw new AssertionError(msg);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java b/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java
index ac7ae34..3e30b9b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MultipleFragmentLoginTest.java
@@ -28,7 +28,6 @@
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
 import android.os.Bundle;
-import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 import android.view.autofill.AutofillValue;
 import android.widget.EditText;
@@ -40,8 +39,8 @@
 public class MultipleFragmentLoginTest extends AutoFillServiceTestCase {
     private static final String LOG_TAG = MultipleFragmentLoginTest.class.getSimpleName();
     @Rule
-    public final ActivityTestRule<FragmentContainerActivity> mActivityRule =
-            new ActivityTestRule<>(FragmentContainerActivity.class);
+    public final AutofillActivityTestRule<FragmentContainerActivity> mActivityRule =
+            new AutofillActivityTestRule<>(FragmentContainerActivity.class);
     private FragmentContainerActivity mActivity;
     private EditText mEditText1;
     private EditText mEditText2;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
index b1250de..d1b8400 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/OptionalSaveActivityTest.java
@@ -28,7 +28,6 @@
 import android.app.assist.AssistStructure;
 import android.autofillservice.cts.CannedFillResponse.CannedDataset;
 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.support.test.rule.ActivityTestRule;
 
 import org.junit.After;
 import org.junit.Before;
@@ -49,8 +48,8 @@
 public class OptionalSaveActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<OptionalSaveActivity> mActivityRule =
-        new ActivityTestRule<OptionalSaveActivity>(OptionalSaveActivity.class);
+    public final AutofillActivityTestRule<OptionalSaveActivity> mActivityRule =
+        new AutofillActivityTestRule<OptionalSaveActivity>(OptionalSaveActivity.class);
 
     private OptionalSaveActivity mActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index cd854c8..d458940 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -25,6 +25,7 @@
 import static android.autofillservice.cts.GridActivity.ID_L4C2;
 import static android.autofillservice.cts.Helper.assertTextIsSanitized;
 import static android.autofillservice.cts.Helper.assertValue;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.Helper.getMaxPartitions;
 import static android.autofillservice.cts.Helper.setMaxPartitions;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
@@ -45,7 +46,6 @@
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.service.autofill.FillResponse;
-import android.support.test.rule.ActivityTestRule;
 import android.widget.RemoteViews;
 
 import org.junit.Before;
@@ -58,8 +58,8 @@
 public class PartitionedActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<GridActivity> mActivityRule =
-        new ActivityTestRule<GridActivity>(GridActivity.class);
+    public final AutofillActivityTestRule<GridActivity> mActivityRule =
+        new AutofillActivityTestRule<GridActivity>(GridActivity.class);
 
     private GridActivity mActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
index 349149f..75c742f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PreFilledLoginActivityTest.java
@@ -27,7 +27,6 @@
 
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.support.test.rule.ActivityTestRule;
 
 import org.junit.After;
 import org.junit.Before;
@@ -40,8 +39,8 @@
 public class PreFilledLoginActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<PreFilledLoginActivity> mActivityRule =
-            new ActivityTestRule<PreFilledLoginActivity>(PreFilledLoginActivity.class);
+    public final AutofillActivityTestRule<PreFilledLoginActivity> mActivityRule =
+            new AutofillActivityTestRule<PreFilledLoginActivity>(PreFilledLoginActivity.class);
 
     private PreFilledLoginActivity mActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
index c5a0105..1601512 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -24,6 +24,7 @@
 import static android.autofillservice.cts.Helper.assertTextAndValue;
 import static android.autofillservice.cts.Helper.eventually;
 import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.Helper.getOutOfProcessPid;
 import static android.autofillservice.cts.Helper.runShellCommand;
 import static android.autofillservice.cts.Helper.setOrientation;
@@ -56,8 +57,8 @@
     private static final String CANCEL_FULL_ID = "android.autofillservice.cts:id/cancel";
 
     @Before
-    public void removeAllSessions() {
-        destroyAllSessions();
+    public void cleanUpState() {
+        Helper.preTestCleanup();
     }
 
     /**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
index d8651b6..8135eba 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TimePickerClockActivityTest.java
@@ -15,15 +15,13 @@
  */
 package android.autofillservice.cts;
 
-import android.support.test.rule.ActivityTestRule;
-
 import org.junit.Rule;
 
 public class TimePickerClockActivityTest extends TimePickerTestCase<TimePickerClockActivity> {
 
     @Rule
-    public final ActivityTestRule<TimePickerClockActivity> mActivityRule =
-        new ActivityTestRule<TimePickerClockActivity>(TimePickerClockActivity.class);
+    public final AutofillActivityTestRule<TimePickerClockActivity> mActivityRule =
+        new AutofillActivityTestRule<TimePickerClockActivity>(TimePickerClockActivity.class);
 
     @Override
     protected TimePickerClockActivity getTimePickerActivity() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
index ab86255..2d97f03 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/TimePickerSpinnerActivityTest.java
@@ -15,15 +15,13 @@
  */
 package android.autofillservice.cts;
 
-import android.support.test.rule.ActivityTestRule;
-
 import org.junit.Rule;
 
 public class TimePickerSpinnerActivityTest extends TimePickerTestCase<TimePickerSpinnerActivity> {
 
     @Rule
-    public final ActivityTestRule<TimePickerSpinnerActivity> mActivityRule =
-        new ActivityTestRule<TimePickerSpinnerActivity>(TimePickerSpinnerActivity.class);
+    public final AutofillActivityTestRule<TimePickerSpinnerActivity> mActivityRule =
+        new AutofillActivityTestRule<TimePickerSpinnerActivity>(TimePickerSpinnerActivity.class);
 
     @Override
     protected TimePickerSpinnerActivity getTimePickerActivity() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
index f33d6fe..541250b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
@@ -24,7 +24,6 @@
 import android.support.annotation.IdRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.autofill.AutofillValue;
@@ -40,8 +39,8 @@
 @RunWith(AndroidJUnit4.class)
 public class ViewAttributesTest extends AutoFillServiceTestCase {
     @Rule
-    public final ActivityTestRule<ViewAttributesTestActivity> mActivityRule =
-            new ActivityTestRule<>(ViewAttributesTestActivity.class);
+    public final AutofillActivityTestRule<ViewAttributesTestActivity> mActivityRule =
+            new AutofillActivityTestRule<>(ViewAttributesTestActivity.class);
 
     private ViewAttributesTestActivity mActivity;
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
index f5e6832..a4d827d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
@@ -36,7 +36,8 @@
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
 import android.autofillservice.cts.VirtualContainerView.Line;
 import android.graphics.Rect;
-import android.support.test.rule.ActivityTestRule;
+import android.os.SystemClock;
+import android.service.autofill.SaveInfo;
 import android.support.test.uiautomator.UiObject2;
 import android.view.autofill.AutofillManager;
 
@@ -51,8 +52,8 @@
 public class VirtualContainerActivityTest extends AutoFillServiceTestCase {
 
     @Rule
-    public final ActivityTestRule<VirtualContainerActivity> mActivityRule =
-            new ActivityTestRule<VirtualContainerActivity>(VirtualContainerActivity.class);
+    public final AutofillActivityTestRule<VirtualContainerActivity> mActivityRule =
+            new AutofillActivityTestRule<VirtualContainerActivity>(VirtualContainerActivity.class);
 
     private VirtualContainerActivity mActivity;