Not crashing tests when a test fails to deinitialize

This causes nondescript diags "Test failed to run to completion.
Reason: 'Instrumentation run failed due to 'Process crashed.''. Check
device logcat for details"

Now quietly skipping all consequent tests after such failure.

Change-Id: I3747cda1a3094bfe82e27eae39ba9e9dfd4af9b6
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 19997eb..15afa90 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -183,16 +183,8 @@
 
     @After
     public void verifyLauncherState() {
-        try {
-            // Limits UI tests affecting tests running after them.
-            mLauncher.waitForLauncherInitialized();
-        } catch (Throwable t) {
-            Log.e(TAG,
-                    "Couldn't deinit after a test, exiting tests, see logs for failures that "
-                            + "could have caused this",
-                    t);
-            exit(1);
-        }
+        // Limits UI tests affecting tests running after them.
+        mLauncher.waitForLauncherInitialized();
     }
 
     protected void clearLauncherData() throws IOException, InterruptedException {
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index cdda0f0..7763cc2 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -8,6 +8,7 @@
 
 import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -15,6 +16,7 @@
 
 public class FailureWatcher extends TestWatcher {
     private static final String TAG = "FailureWatcher";
+    private static boolean sHadFailedTestDeinitialization;
     final private UiDevice mDevice;
 
     public FailureWatcher(UiDevice device) {
@@ -60,4 +62,31 @@
 
         device.takeScreenshot(new File(pathname));
     }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+
+            @Override
+            public void evaluate() throws Throwable {
+                if (sHadFailedTestDeinitialization) {
+                    Log.d(TAG, "Skipping due to a recent test deinitialization failure: " +
+                            description.getDisplayName());
+                    return;
+                }
+
+                try {
+                    base.evaluate();
+                } catch (Throwable e) {
+                    if (!Log.getStackTraceString(e).contains(
+                            "androidx.test.internal.runner.junit4.statement.RunBefores.evaluate")) {
+                        // Test failed to deinitialize. Since the global state is probably
+                        // corrupted, won't execute other tests.
+                        sHadFailedTestDeinitialization = true;
+                    }
+                    throw e;
+                }
+            }
+        };
+    }
 }