Merge "Updating feature flags subclassing" into ub-launcher3-master
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 9a3a379..3278960 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -496,7 +496,7 @@
             // In transposed layout, we add the QSB in the Grid. As workspace does not touch the
             // edges, we do not need a full width QSB.
             qsb = LayoutInflater.from(getContext())
-                    .inflate(R.layout.search_container_workspace,firstPage, false);
+                    .inflate(R.layout.search_container_workspace, firstPage, false);
         }
 
         CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), 1);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index a70072c..d63d2dd 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -123,6 +123,10 @@
             "ENABLE_DATABASE_RESTORE", true,
             "Enable database restore when new restore session is created");
 
+    public static final TogglableFlag ENABLE_UNIVERSAL_SMARTSPACE = new TogglableFlag(
+            "ENABLE_UNIVERSAL_SMARTSPACE", false,
+            "Replace Smartspace with a version rendered by System UI.");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/tests/src/com/android/launcher3/util/rule/FailureInvestigator.java b/tests/src/com/android/launcher3/util/rule/FailureInvestigator.java
new file mode 100644
index 0000000..56c885d
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/FailureInvestigator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 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 com.android.launcher3.util.rule;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import androidx.test.uiautomator.UiDevice;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+class FailureInvestigator {
+    private static boolean matches(String regex, CharSequence string) {
+        return Pattern.compile(regex).matcher(string).find();
+    }
+
+    static int getBugForFailure(CharSequence exception, String testsStartTime) {
+        final String logSinceTestsStart;
+        try {
+            logSinceTestsStart =
+                    UiDevice.getInstance(getInstrumentation())
+                            .executeShellCommand("logcat -d -t " + testsStartTime.replace(" ", ""));
+        } catch (IOException e) {
+            return 0;
+        }
+
+        if (matches(
+                "java.lang.AssertionError: http://go/tapl : Tests are broken by a non-Launcher "
+                        + "system error: Phone is locked",
+                exception)) {
+            if (matches(
+                    "BroadcastQueue: Can't deliver broadcast to com.android.systemui.*Crashing it",
+                    logSinceTestsStart)) {
+                return 147845913;
+            }
+        }
+
+        return 0;
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index cdda0f0..feb89b9 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -8,10 +8,13 @@
 
 import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 public class FailureWatcher extends TestWatcher {
     private static final String TAG = "FailureWatcher";
@@ -35,6 +38,30 @@
         }
     }
 
+    private static final String testsStartTime =
+            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date());
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                try {
+                    base.evaluate();
+                } catch (Throwable e) {
+                    final int bug =
+                            FailureInvestigator.getBugForFailure(e.toString(), testsStartTime);
+                    if (bug == 0) throw e;
+
+                    Log.e(TAG, "Known bug found for the original failure "
+                            + android.util.Log.getStackTraceString(e));
+                    throw new AssertionError(
+                            "Detected a failure that matches a known bug b/" + bug);
+                }
+            }
+        };
+    }
+
     @Override
     protected void failed(Throwable e, Description description) {
         onError(mDevice, description, e);
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 6df8790..3670392 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -385,7 +385,7 @@
         log("Hierarchy dump for: " + message);
         dumpViewHierarchy();
 
-        final String eventMismatch = getEventMismatchMessage();
+        final String eventMismatch = getEventMismatchMessage(false);
 
         if (eventMismatch != null) {
             message = message + ",\nhaving produced wrong events:\n    " + eventMismatch;
@@ -1172,14 +1172,7 @@
                 return; // There was a failure. Noo need to report another one.
             }
 
-            // Wait until Launcher generates expected number of events.
-            final long endTime = SystemClock.uptimeMillis() + WAIT_TIME_MS;
-            while (SystemClock.uptimeMillis() < endTime
-                    && getEvents().size() < mExpectedEvents.size()) {
-                SystemClock.sleep(100);
-            }
-
-            final String message = getEventMismatchMessage();
+            final String message = getEventMismatchMessage(true);
             if (message != null) {
                 Assert.fail(formatSystemHealthMessage(
                         "http://go/tapl : unexpected event sequence: " + message));
@@ -1191,11 +1184,21 @@
         if (mExpectedEvents != null) mExpectedEvents.add(expected);
     }
 
-    private String getEventMismatchMessage() {
+    private String getEventMismatchMessage(boolean waitForExpectedCount) {
         if (mExpectedEvents == null) return null;
 
         try {
-            final List<String> actual = getEvents();
+            List<String> actual = getEvents();
+
+            if (waitForExpectedCount) {
+                // Wait until Launcher generates the expected number of events.
+                final long endTime = SystemClock.uptimeMillis() + WAIT_TIME_MS;
+                while (SystemClock.uptimeMillis() < endTime
+                        && actual.size() < mExpectedEvents.size()) {
+                    SystemClock.sleep(100);
+                    actual = getEvents();
+                }
+            }
 
             for (int i = 0; i < mExpectedEvents.size(); ++i) {
                 if (i >= actual.size()) {