Merge "Improving tests to fix testBindNormalWidget_withoutConfig, and beyond" into ub-launcher3-master
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index d571cf4..cbfde25 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -451,6 +451,11 @@
      * @return true if the page could be bound synchronously.
      */
     public boolean startLoader(int synchronousBindPage) {
+        if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
+                && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
+            android.util.Log.d("b/117332845",
+                    android.util.Log.getStackTraceString(new Throwable()));
+        }
         // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
         InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
         synchronized (mLock) {
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 773ec9d..6db784a 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -47,6 +47,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.MainThreadExecutor;
@@ -133,7 +134,8 @@
                     try {
                         // Create launcher activity if necessary and bring it to the front.
                         mDevice.pressHome();
-                        waitForLauncherCondition(launcher -> launcher != null);
+                        waitForLauncherCondition("Launcher activity wasn't created",
+                                launcher -> launcher != null);
 
                         executeOnLauncher(launcher ->
                                 launcher.getRotationHelper().forceAllowRotationForTesting(true));
@@ -170,7 +172,7 @@
     @After
     public void tearDown() throws Exception {
         // Limits UI tests affecting tests running after them.
-        resetLoaderState();
+        waitForModelLoaded();
     }
 
     protected void lockRotation(boolean naturalOrientation) throws RemoteException {
@@ -320,8 +322,7 @@
         } catch (Throwable t) {
             throw new IllegalArgumentException(t);
         }
-        waitForLauncherCondition(launcher ->
-                LauncherAppState.getInstance(mTargetContext).getModel().isModelLoaded());
+        waitForModelLoaded();
         if (com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
                 && com.android.launcher3.Utilities.IS_DEBUG_DEVICE) {
             android.util.Log.d("b/117332845",
@@ -329,6 +330,13 @@
         }
     }
 
+    protected void waitForModelLoaded() {
+        waitForLauncherCondition("Launcher model didn't load", launcher -> {
+            final LauncherModel model = LauncherAppState.getInstance(mTargetContext).getModel();
+            return model.getCallback() == null || model.isModelLoaded();
+        });
+    }
+
     /**
      * Runs the callback on the UI thread and returns the result.
      */
@@ -354,22 +362,23 @@
 
     // Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call expecting
     // the results of that gesture because the wait can hide flakeness.
-    protected boolean waitForState(LauncherState state) {
-        return waitForLauncherCondition(launcher -> launcher.getStateManager().getState() == state);
+    protected void waitForState(String message, LauncherState state) {
+        waitForLauncherCondition(message,
+                launcher -> launcher.getStateManager().getState() == state);
     }
 
     // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
     // flakiness.
-    protected boolean waitForLauncherCondition(Function<Launcher, Boolean> condition) {
-        return waitForLauncherCondition(condition, DEFAULT_ACTIVITY_TIMEOUT);
+    protected void waitForLauncherCondition(String message, Function<Launcher, Boolean> condition) {
+        waitForLauncherCondition(message, condition, DEFAULT_ACTIVITY_TIMEOUT);
     }
 
     // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
     // flakiness.
-    protected boolean waitForLauncherCondition(
-            Function<Launcher, Boolean> condition, long timeout) {
-        if (!TestHelpers.isInLauncherProcess()) return true;
-        return Wait.atMost(() -> getFromLauncher(condition), timeout);
+    protected void waitForLauncherCondition(
+            String message, Function<Launcher, Boolean> condition, long timeout) {
+        if (!TestHelpers.isInLauncherProcess()) return;
+        Wait.atMost(message, () -> getFromLauncher(condition), timeout);
     }
 
     /**
diff --git a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
index 600d390..a6830fc 100644
--- a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
@@ -46,7 +46,7 @@
 
         // Open all apps and wait for load complete.
         final UiObject2 appsContainer = openAllApps();
-        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+        Wait.atMost(null, Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT);
 
         // Drag icon to homescreen.
         UiObject2 icon = scrollAndFind(appsContainer, By.text(settingsApp.getLabel().toString()));
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
index 6a007ae..f773000 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
@@ -47,8 +47,7 @@
 
         // Open all apps and wait for load complete
         final UiObject2 appsContainer = openAllApps();
-        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2),
-                DEFAULT_UI_TIMEOUT));
+        Wait.atMost(null, Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT);
 
         // Find settings app and verify shortcuts appear when long pressed
         UiObject2 icon = scrollAndFind(appsContainer, By.text(testApp.getLabel().toString()));
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
index c23f6ef..bc1b519 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
@@ -49,8 +49,7 @@
 
         // Open all apps and wait for load complete.
         final UiObject2 appsContainer = openAllApps();
-        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2),
-                DEFAULT_UI_TIMEOUT));
+        Wait.atMost(null, Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT);
 
         // Find the app and long press it to show shortcuts.
         UiObject2 icon = scrollAndFind(appsContainer, By.text(testApp.getLabel().toString()));
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 83fcc60..14141f0 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -106,7 +106,7 @@
 
         // Open widget tray and wait for load complete.
         final UiObject2 widgetContainer = openWidgetsTray();
-        assertTrue(Wait.atMost(Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT));
+        Wait.atMost(null, Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT);
 
         // Drag widget to homescreen
         WidgetConfigStartupMonitor monitor = new WidgetConfigStartupMonitor();
@@ -128,12 +128,12 @@
 
         setResult(acceptConfig);
         if (acceptConfig) {
-            assertTrue(Wait.atMost(new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT));
+            Wait.atMost(null, new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT);
             assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
         } else {
             // Verify that the widget id is deleted.
-            assertTrue(Wait.atMost(() -> mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null,
-                    DEFAULT_ACTIVITY_TIMEOUT));
+            Wait.atMost(null, () -> mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null,
+                    DEFAULT_ACTIVITY_TIMEOUT);
         }
     }
 
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index d9fef81..8a05e2c 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -70,7 +70,7 @@
 
         // Open widget tray and wait for load complete.
         final UiObject2 widgetContainer = openWidgetsTray();
-        assertTrue(Wait.atMost(Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT));
+        Wait.atMost(null, Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT);
 
         // Drag widget to homescreen
         UiObject2 widget = scrollAndFind(widgetContainer, By.clazz(WidgetCell.class)
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 738ad84..b7342c4 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -141,7 +141,6 @@
         // Since there is no widget to verify, just wait until the workspace is ready.
         setupAndVerifyContents(item, Workspace.class, null);
 
-        waitUntilLoaderIdle();
         // Item deleted from db
         mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
                 null, null, null, null, null);
@@ -187,7 +186,6 @@
         item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID;
 
         setupAndVerifyContents(item, PendingAppWidgetHostView.class, null);
-        waitUntilLoaderIdle();
         // Item deleted from db
         mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
                 null, null, null, null, null);
@@ -216,7 +214,6 @@
         // The view does not exist
         assertFalse(mDevice.findObject(
                 new UiSelector().className(PendingAppWidgetHostView.class)).exists());
-        waitUntilLoaderIdle();
         // Item deleted from db
         mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
                 null, null, null, null, null);
@@ -234,7 +231,6 @@
 
         setupAndVerifyContents(item, PendingAppWidgetHostView.class, null);
         // Verify item still exists in db
-        waitUntilLoaderIdle();
         mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
                 null, null, null, null, null);
         assertEquals(1, mCursor.getCount());
@@ -261,7 +257,6 @@
 
         setupAndVerifyContents(item, PendingAppWidgetHostView.class, null);
         // Verify item still exists in db
-        waitUntilLoaderIdle();
         mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
                 null, null, null, null, null);
         assertEquals(1, mCursor.getCount());
@@ -306,6 +301,8 @@
 
         // Launch the home activity
         mActivityMonitor.startLauncher();
+        waitForModelLoaded();
+
         // Verify UI
         UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
                 .className(widgetClass);
@@ -390,15 +387,4 @@
         item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
         return item;
     }
-
-    /**
-     * Blocks the current thread until all the jobs in the main worker thread are complete.
-     */
-    private void waitUntilLoaderIdle() throws Exception {
-        new LooperExecutor(LauncherModel.getWorkerLooper())
-                .submit(new Runnable() {
-                    @Override
-                    public void run() { }
-                }).get(DEFAULT_WORKER_TIMEOUT_SECS, TimeUnit.SECONDS);
-    }
 }
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index 67a7fde..839cfb2 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -152,7 +152,7 @@
 
         // Open all apps and wait for load complete
         final UiObject2 appsContainer = openAllApps();
-        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+        Wait.atMost(null, Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT);
 
         // Open Pin item activity
         BlockingBroadcastReceiver openMonitor = new BlockingBroadcastReceiver(
@@ -191,7 +191,7 @@
 
         // Go back to home
         mActivityMonitor.returnToHome();
-        assertTrue(Wait.atMost(new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT));
+        Wait.atMost(null, new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT);
     }
 
     /**
diff --git a/tests/src/com/android/launcher3/util/Wait.java b/tests/src/com/android/launcher3/util/Wait.java
index f9e53ba..0e41c02 100644
--- a/tests/src/com/android/launcher3/util/Wait.java
+++ b/tests/src/com/android/launcher3/util/Wait.java
@@ -2,6 +2,8 @@
 
 import android.os.SystemClock;
 
+import org.junit.Assert;
+
 /**
  * A utility class for waiting for a condition to be true.
  */
@@ -9,16 +11,16 @@
 
     private static final long DEFAULT_SLEEP_MS = 200;
 
-    public static boolean atMost(Condition condition, long timeout) {
-        return atMost(condition, timeout, DEFAULT_SLEEP_MS);
+    public static void atMost(String message, Condition condition, long timeout) {
+        atMost(message, condition, timeout, DEFAULT_SLEEP_MS);
     }
 
-    public static boolean atMost(Condition condition, long timeout, long sleepMillis) {
+    public static void atMost(String message, Condition condition, long timeout, long sleepMillis) {
         long endTime = SystemClock.uptimeMillis() + timeout;
         while (SystemClock.uptimeMillis() < endTime) {
             try {
                 if (condition.isTrue()) {
-                    return true;
+                    return;
                 }
             } catch (Throwable t) {
                 // Ignore
@@ -29,11 +31,11 @@
         // Check once more before returning false.
         try {
             if (condition.isTrue()) {
-                return true;
+                return;
             }
         } catch (Throwable t) {
             // Ignore
         }
-        return false;
+        Assert.fail(message);
     }
 }