Merge "Improving tests to fix testBindNormalWidget_withoutConfig, and beyond" into ub-launcher3-master
This commit is contained in:
commit
514cd27850
|
@ -451,6 +451,11 @@ public class LauncherModel extends BroadcastReceiver
|
|||
* @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) {
|
||||
|
|
|
@ -47,6 +47,7 @@ import androidx.test.uiautomator.Until;
|
|||
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 @@ public abstract class AbstractLauncherUiTest {
|
|||
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 @@ public abstract class AbstractLauncherUiTest {
|
|||
@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 @@ public abstract class AbstractLauncherUiTest {
|
|||
} 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 @@ public abstract class AbstractLauncherUiTest {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ public abstract class AbstractLauncherUiTest {
|
|||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,7 +46,7 @@ public class AllAppsIconToHomeTest extends AbstractLauncherUiTest {
|
|||
|
||||
// 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()));
|
||||
|
|
|
@ -47,8 +47,7 @@ public class ShortcutsLaunchTest extends AbstractLauncherUiTest {
|
|||
|
||||
// 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()));
|
||||
|
|
|
@ -49,8 +49,7 @@ public class ShortcutsToHomeTest extends AbstractLauncherUiTest {
|
|||
|
||||
// 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()));
|
||||
|
|
|
@ -106,7 +106,7 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest {
|
|||
|
||||
// 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 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest {
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ public class AddWidgetTest extends AbstractLauncherUiTest {
|
|||
|
||||
// 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)
|
||||
|
|
|
@ -141,7 +141,6 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||
// 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 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||
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 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||
// 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 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||
|
||||
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 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||
|
||||
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 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||
|
||||
// Launch the home activity
|
||||
mActivityMonitor.startLauncher();
|
||||
waitForModelLoaded();
|
||||
|
||||
// Verify UI
|
||||
UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
|
||||
.className(widgetClass);
|
||||
|
@ -390,15 +387,4 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ public class RequestPinItemTest extends AbstractLauncherUiTest {
|
|||
|
||||
// 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 @@ public class RequestPinItemTest extends AbstractLauncherUiTest {
|
|||
|
||||
// Go back to home
|
||||
mActivityMonitor.returnToHome();
|
||||
assertTrue(Wait.atMost(new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT));
|
||||
Wait.atMost(null, new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.android.launcher3.util;
|
|||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
* A utility class for waiting for a condition to be true.
|
||||
*/
|
||||
|
@ -9,16 +11,16 @@ public class Wait {
|
|||
|
||||
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 @@ public class Wait {
|
|||
// Check once more before returning false.
|
||||
try {
|
||||
if (condition.isTrue()) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// Ignore
|
||||
}
|
||||
return false;
|
||||
Assert.fail(message);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue