Saving test artifacts in TAPL when the failure is diagnosed

Not waiting for FailureWatcher to catch the exception and save
artifacts. This will help to save test artifacts before potential
deinitialization in the test which may change the screen contents.

Bug: 187761685
Test: presubmit
Flag: N/A
Change-Id: I7aa95028acfae3fe0895fc5df4ea6f6912fcda52
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index df88726..094fd4c 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -205,11 +205,10 @@
             boolean condition, Description description) {
         launcher.checkForAnomaly(true, true);
         if (!condition) {
-            final AssertionError assertionError = new AssertionError(message);
             if (description != null) {
-                FailureWatcher.onError(launcher, description, assertionError);
+                FailureWatcher.onError(launcher, description);
             }
-            throw assertionError;
+            throw new AssertionError(message);
         }
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
index e5657fb..84ceb33 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java
@@ -130,11 +130,10 @@
             boolean condition, Description description) {
         launcher.checkForAnomaly(true, true);
         if (!condition) {
-            final AssertionError assertionError = new AssertionError(message);
             if (description != null) {
-                FailureWatcher.onError(launcher, description, assertionError);
+                FailureWatcher.onError(launcher, description);
             }
-            throw assertionError;
+            throw new AssertionError(message);
         }
     }
 }
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index c4e74f2..e5c5c19 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -57,7 +57,7 @@
                                         true));
 
                     } catch (Throwable e) {
-                        FailureWatcher.onError(mTest.mLauncher, description, e);
+                        FailureWatcher.onError(mTest.mLauncher, description);
                         throw e;
                     }
 
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 7fba33e..7bdc040 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -30,6 +30,8 @@
 public class FailureWatcher extends TestWatcher {
     private static final String TAG = "FailureWatcher";
     private static boolean sSavedBugreport = false;
+    private static Description sDescriptionForLastSavedArtifacts;
+
     private final LauncherInstrumentation mLauncher;
     @NonNull
     private final Supplier<ExportedData> mViewCaptureDataSupplier;
@@ -41,6 +43,18 @@
     }
 
     @Override
+    protected void starting(Description description) {
+        mLauncher.setOnFailure(() -> onError(mLauncher, description, mViewCaptureDataSupplier));
+        super.starting(description);
+    }
+
+    @Override
+    protected void finished(Description description) {
+        super.finished(description);
+        mLauncher.setOnFailure(null);
+    }
+
+    @Override
     protected void succeeded(Description description) {
         super.succeeded(description);
         AbstractLauncherUiTest.checkDetectedLeaks(mLauncher);
@@ -70,7 +84,7 @@
 
     @Override
     protected void failed(Throwable e, Description description) {
-        onError(mLauncher, description, e, mViewCaptureDataSupplier);
+        onError(mLauncher, description, mViewCaptureDataSupplier);
     }
 
     static File diagFile(Description description, String prefix, String ext) {
@@ -79,13 +93,18 @@
                         + description.getMethodName() + "." + ext);
     }
 
-    public static void onError(LauncherInstrumentation launcher, Description description,
-            Throwable e) {
-        onError(launcher, description, e, null);
+    /** Action executed when an error condition is expected. Saves artifacts. */
+    public static void onError(LauncherInstrumentation launcher, Description description) {
+        onError(launcher, description, null);
     }
 
     private static void onError(LauncherInstrumentation launcher, Description description,
-            Throwable e, @Nullable Supplier<ExportedData> viewCaptureDataSupplier) {
+            @Nullable Supplier<ExportedData> viewCaptureDataSupplier) {
+        if (description.equals(sDescriptionForLastSavedArtifacts)) {
+            // This test has already saved its artifacts.
+            return;
+        }
+        sDescriptionForLastSavedArtifacts = description;
 
         final File sceenshot = diagFile(description, "TestScreenshot", "png");
         final File hierarchy = diagFile(description, "Hierarchy", "zip");
@@ -114,7 +133,7 @@
         Log.e(TAG, "Failed test " + description.getMethodName()
                 + ",\nscreenshot will be saved to " + sceenshot
                 + ",\nUI dump at: " + hierarchy
-                + " (use go/web-hv to open the dump file)", e);
+                + " (use go/web-hv to open the dump file)");
         final UiDevice device = launcher.getDevice();
         device.takeScreenshot(sceenshot);
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index ba8121f..0eaf6a8 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -204,6 +204,7 @@
     private Runnable mTestAnomalyChecker;
 
     private boolean mCheckEventsForSuccessfulGestures = false;
+    private Runnable mOnFailure;
     private Runnable mOnLauncherCrashed;
 
     private TrackpadGestureType mTrackpadGestureType = TrackpadGestureType.NONE;
@@ -342,6 +343,11 @@
         mCheckEventsForSuccessfulGestures = true;
     }
 
+    /** Sets a runnable that will be invoked upon assertion failures. */
+    public void setOnFailure(Runnable onFailure) {
+        mOnFailure = onFailure;
+    }
+
     public void setOnLauncherCrashed(Runnable onLauncherCrashed) {
         mOnLauncherCrashed = onLauncherCrashed;
     }
@@ -623,6 +629,7 @@
         final String systemAnomalyMessage =
                 getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews);
         if (systemAnomalyMessage != null) {
+            if (mOnFailure != null) mOnFailure.run();
             Assert.fail(formatSystemHealthMessage(formatErrorWithEvents(
                     "http://go/tapl : Tests are broken by a non-Launcher system error: "
                             + systemAnomalyMessage, false)));
@@ -742,6 +749,7 @@
 
     void fail(String message) {
         checkForAnomaly();
+        if (mOnFailure != null) mOnFailure.run();
         Assert.fail(formatSystemHealthMessage(formatErrorWithEvents(
                 "http://go/tapl test failure: " + message + ";\nContext: " + getContextDescription()
                         + "; now visible state is " + getVisibleStateMessage(), true)));