Merge "Simplifying some test utility methods" into udc-qpr-dev am: 859d0d87e2

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/23443976

Change-Id: I8894188d382d41196bed569b366ba60f2ec6ae64
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
TreeHugger Robot
2023-06-05 23:22:21 +00:00
committed by Automerger Merge Worker
18 changed files with 171 additions and 193 deletions
@@ -858,8 +858,11 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
.setDuration(isStashed ? duration / 2 : duration));
}
private static void play(AnimatorSet as, Animator a, long startDelay, long duration,
private static void play(AnimatorSet as, @Nullable Animator a, long startDelay, long duration,
Interpolator interpolator) {
if (a == null) {
return;
}
a.setDuration(duration);
a.setStartDelay(startDelay);
a.setInterpolator(interpolator);
@@ -187,7 +187,7 @@ public class ViewInflationDuringSwipeUp extends AbstractQuickStepTest {
LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
LauncherSettings.Settings.call(mResolver,
LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(false);
// Make sure the widget is big enough to show a list of items
info.minSpanX = 2;
info.minSpanY = 2;
@@ -33,6 +33,7 @@ import android.text.TextUtils;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
import java.util.Locale;
import java.util.Objects;
@@ -92,6 +93,9 @@ public class DeviceGridState implements Comparable<DeviceGridState> {
* Stores the device state to shared preferences
*/
public void writeToPrefs(Context context) {
if (context instanceof SandboxContext) {
return;
}
LauncherPrefs.get(context).put(
WORKSPACE_SIZE.to(mGridSizeString),
HOTSEAT_COUNT.to(mNumHotseat),
@@ -45,7 +45,6 @@ import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
@@ -133,10 +132,8 @@ public class GridSizeMigrationUtil {
Log.v(TAG, "Workspace migration completed in "
+ (System.currentTimeMillis() - migrationStartTime));
if (!(context instanceof SandboxContext)) {
// Save current configuration, so that the migration does not run again.
destDeviceState.writeToPrefs(context);
}
// Save current configuration, so that the migration does not run again.
destDeviceState.writeToPrefs(context);
}
}
@@ -367,18 +367,9 @@ public class LoaderTask implements Runnable {
final boolean isSdCardReady = Utilities.isBootCompleted();
final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context);
boolean clearDb = false;
if (!mApp.getModel().getModelDbController().migrateGridIfNeeded()) {
// Migration failed. Clear workspace.
clearDb = true;
}
if (clearDb) {
Log.d(TAG, "loadWorkspace: resetting launcher database");
Settings.call(contentResolver, Settings.METHOD_CREATE_EMPTY_DB);
}
mApp.getModel().getModelDbController().tryMigrateDB();
Log.d(TAG, "loadWorkspace: loading default favorites");
mApp.getModel().getModelDbController().loadDefaultFavoritesIfNecessary();
Settings.call(contentResolver, Settings.METHOD_LOAD_DEFAULT_FAVORITES);
synchronized (mBgDataModel) {
@@ -280,13 +280,29 @@ public class ModelDbController {
mOpenHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
}
/**
* Migrates the DB if needed. If the migration failed, it clears the DB.
*/
public void tryMigrateDB() {
if (!migrateGridIfNeeded()) {
Log.d(TAG, "Migration failed: resetting launcher database");
createEmptyDB();
LauncherPrefs.get(mContext).putSync(
getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
// Write the grid state to avoid another migration
new DeviceGridState(LauncherAppState.getIDP(mContext)).writeToPrefs(mContext);
}
}
/**
* Migrates the DB if needed, and returns false if the migration failed
* and DB needs to be cleared.
* @return true if migration was success or ignored, false if migration failed
* and the DB should be reset.
*/
public boolean migrateGridIfNeeded() {
private boolean migrateGridIfNeeded() {
createDbIfNotExists();
InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
if (!GridSizeMigrationUtil.needsToMigrate(mContext, idp)) {
@@ -15,62 +15,80 @@
*/
package com.android.launcher3.celllayout;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.ContentWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
public class FavoriteItemsTransaction {
private ArrayList<ItemInfo> mItemsToSubmit;
private ArrayList<Supplier<ItemInfo>> mItemsToSubmit;
private Context mContext;
private ContentResolver mResolver;
public AbstractLauncherUiTest mTest;
public FavoriteItemsTransaction(Context context, AbstractLauncherUiTest test) {
public FavoriteItemsTransaction(Context context) {
mItemsToSubmit = new ArrayList<>();
mContext = context;
mResolver = mContext.getContentResolver();
mTest = test;
}
public FavoriteItemsTransaction addItem(ItemInfo itemInfo) {
public FavoriteItemsTransaction addItem(Supplier<ItemInfo> itemInfo) {
this.mItemsToSubmit.add(itemInfo);
return this;
}
public FavoriteItemsTransaction removeLast() {
this.mItemsToSubmit.remove(this.mItemsToSubmit.size() - 1);
return this;
}
/**
* Commits all the ItemInfo into the database of Favorites
**/
public void commit() throws ExecutionException, InterruptedException {
List<ContentValues> values = new ArrayList<>();
for (ItemInfo item : this.mItemsToSubmit) {
ContentWriter writer = new ContentWriter(mContext);
item.onAddToDatabase(writer);
writer.put(LauncherSettings.Favorites._ID, item.id);
values.add(writer.getValues(mContext));
}
// Submit the icons to the database in the model thread to prevent race conditions
MODEL_EXECUTOR.submit(() -> mResolver.bulkInsert(LauncherSettings.Favorites.CONTENT_URI,
values.toArray(new ContentValues[0]))).get();
// Reload the state of the Launcher
MAIN_EXECUTOR.submit(() -> LauncherAppState.getInstance(
mContext).getModel().forceReload()).get();
public void commit() {
LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
// Load the model once so that there is no pending migration:
loadModelSync(model);
runOnExecutorSync(MODEL_EXECUTOR, () -> {
ModelDbController controller = model.getModelDbController();
// Migrate any previous data so that the DB state is correct
controller.tryMigrateDB();
// Create DB again to load fresh data
controller.createEmptyDB();
controller.clearEmptyDbFlag();
// Add new data
List<ContentValues> values = new ArrayList<>();
int count = mItemsToSubmit.size();
for (int i = 0; i < count; i++) {
ContentWriter writer = new ContentWriter(mContext);
mItemsToSubmit.get(i).get().onAddToDatabase(writer);
writer.put(LauncherSettings.Favorites._ID, i);
values.add(writer.getValues(mContext));
}
controller.bulkInsert(TABLE_NAME, values.toArray(new ContentValues[0]));
});
// Reload model
runOnExecutorSync(MAIN_EXECUTOR, model::forceReload);
loadModelSync(model);
}
private void loadModelSync(LauncherModel model) {
Callbacks mockCb = new Callbacks() { };
runOnExecutorSync(MAIN_EXECUTOR, () -> model.addCallbacksAndLoad(mockCb));
runOnExecutorSync(MODEL_EXECUTOR, () -> { });
runOnExecutorSync(MAIN_EXECUTOR, () -> { });
runOnExecutorSync(MAIN_EXECUTOR, () -> model.removeCallbacks(mockCb));
}
}
@@ -59,7 +59,7 @@ public class ReorderWidgets extends AbstractLauncherUiTest {
@Before
public void setup() throws Throwable {
mWorkspaceBuilder = new TestWorkspaceBuilder(this, mTargetContext);
mWorkspaceBuilder = new TestWorkspaceBuilder(mTargetContext);
TaplTestsLauncher3.initialize(this);
clearHomescreen();
}
@@ -108,7 +108,7 @@ public class ReorderWidgets extends AbstractLauncherUiTest {
testCase.mStart);
FavoriteItemsTransaction transaction =
new FavoriteItemsTransaction(mTargetContext, this);
new FavoriteItemsTransaction(mTargetContext);
transaction = buildWorkspaceFromBoards(testCase.mStart, transaction);
transaction.commit();
// resetLoaderState triggers the launcher to start loading the workspace which allows
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.celllayout;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.android.launcher3.ui.TestViewHelpers.findWidgetProvider;
import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
import android.content.ComponentName;
@@ -25,33 +28,29 @@ import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import java.util.function.Supplier;
import java.util.stream.IntStream;
public class TestWorkspaceBuilder {
private static final String TAG = "CellLayoutBoardBuilder";
private static final ComponentName APP_COMPONENT_NAME = new ComponentName(
"com.google.android.calculator", "com.android.calculator2.Calculator");
public AbstractLauncherUiTest mTest;
private UserHandle mMyUser;
private Context mContext;
private ContentResolver mResolver;
public TestWorkspaceBuilder(AbstractLauncherUiTest test, Context context) {
mTest = test;
public TestWorkspaceBuilder(Context context) {
mMyUser = Process.myUserHandle();
mContext = context;
mResolver = mContext.getContentResolver();
@@ -68,10 +67,9 @@ public class TestWorkspaceBuilder {
for (int y = initY; y < initY + widgetRect.getSpanY(); y++) {
try {
// this widgets are filling, we don't care if we can't place them
ItemInfo item = createWidgetInCell(
transaction.addItem(createWidgetInCell(
new CellLayoutBoard.WidgetRect(CellLayoutBoard.CellType.IGNORE,
new Rect(x, y, x, y)), screenId);
transaction.addItem(item);
new Rect(x, y, x, y)), screenId));
} catch (Exception e) {
Log.d(TAG, "Unable to place filling widget at " + x + "," + y);
}
@@ -108,7 +106,7 @@ public class TestWorkspaceBuilder {
board.getWidgets().forEach(
(widgetRect) -> addCorrespondingWidgetRect(widgetRect, transaction, screenId));
board.getIcons().forEach((iconPoint) ->
transaction.addItem(createIconInCell(iconPoint, screenId))
transaction.addItem(() -> createIconInCell(iconPoint, screenId))
);
return transaction;
}
@@ -118,24 +116,25 @@ public class TestWorkspaceBuilder {
* be clean otherwise this doesn't overrides the existing icons.
*/
public FavoriteItemsTransaction fillHotseatIcons(FavoriteItemsTransaction transaction) {
int hotseatCount = InvariantDeviceProfile.INSTANCE.get(mContext).numDatabaseHotseatIcons;
for (int i = 0; i < hotseatCount; i++) {
transaction.addItem(getHotseatValues(i));
}
IntStream.range(0, InvariantDeviceProfile.INSTANCE.get(mContext).numDatabaseHotseatIcons)
.forEach(i -> transaction.addItem(() -> getHotseatValues(i)));
return transaction;
}
private ItemInfo createWidgetInCell(CellLayoutBoard.WidgetRect widgetRect, int screenId) {
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(mTest, false);
LauncherAppWidgetInfo item = createWidgetInfo(info,
ApplicationProvider.getApplicationContext(), true);
item.id = getID();
item.cellX = widgetRect.getCellX();
item.cellY = widgetRect.getCellY();
item.spanX = widgetRect.getSpanX();
item.spanY = widgetRect.getSpanY();
item.screenId = screenId;
return item;
private Supplier<ItemInfo> createWidgetInCell(
CellLayoutBoard.WidgetRect widgetRect, int screenId) {
// Create the widget lazily since the appWidgetId can get lost during setup
return () -> {
LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
LauncherAppWidgetInfo item = createWidgetInfo(info, getApplicationContext(), true);
item.id = getID();
item.cellX = widgetRect.getCellX();
item.cellY = widgetRect.getCellY();
item.spanX = widgetRect.getSpanX();
item.spanY = widgetRect.getSpanY();
item.screenId = screenId;
return item;
};
}
private ItemInfo createIconInCell(CellLayoutBoard.IconPoint iconPoint, int screenId) {
@@ -19,6 +19,7 @@ import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.TestUtil.getOnUiThread;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -39,7 +40,6 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.system.OsConstants;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -64,6 +64,7 @@ import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.WidgetUtils;
import com.android.launcher3.util.rule.FailureWatcher;
@@ -82,10 +83,8 @@ import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -98,7 +97,7 @@ public abstract class AbstractLauncherUiTest {
public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
public static final long DEFAULT_UI_TIMEOUT = 10000;
public static final long DEFAULT_UI_TIMEOUT = TestUtil.DEFAULT_UI_TIMEOUT;
private static final String TAG = "AbstractLauncherUiTest";
private static boolean sDumpWasGenerated = false;
@@ -332,22 +331,6 @@ public abstract class AbstractLauncherUiTest {
mLauncher.waitForLauncherInitialized();
}
/**
* Runs the callback on the UI thread and returns the result.
*/
protected <T> T getOnUiThread(final Callable<T> callback) {
try {
return mMainThreadExecutor.submit(callback).get(DEFAULT_UI_TIMEOUT,
TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
Log.e(TAG, "Timeout in getOnUiThread, sending SIGABRT", e);
Process.sendSignal(Process.myPid(), OsConstants.SIGABRT);
throw new RuntimeException(e);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
protected <T> T getFromLauncher(Function<Launcher, T> f) {
if (!TestHelpers.isInLauncherProcess()) return null;
return getOnUiThread(() -> f.apply(mActivityMonitor.getActivity()));
@@ -15,11 +15,14 @@
*/
package com.android.launcher3.ui;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static androidx.test.InstrumentationRegistry.getTargetContext;
import static android.os.Process.myUserHandle;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.util.TestUtil.getOnUiThread;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.os.Process;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -29,7 +32,6 @@ import com.android.launcher3.testcomponent.AppWidgetWithConfig;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
import java.util.concurrent.Callable;
import java.util.function.Function;
public class TestViewHelpers {
@@ -38,23 +40,16 @@ public class TestViewHelpers {
/**
* Finds a widget provider which can fit on the home screen.
*
* @param test test suite.
* @param hasConfigureScreen if true, a provider with a config screen is returned.
*/
public static LauncherAppWidgetProviderInfo findWidgetProvider(AbstractLauncherUiTest test,
final boolean hasConfigureScreen) {
LauncherAppWidgetProviderInfo info =
test.getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
@Override
public LauncherAppWidgetProviderInfo call() throws Exception {
ComponentName cn = new ComponentName(getInstrumentation().getContext(),
hasConfigureScreen ? AppWidgetWithConfig.class
: AppWidgetNoConfig.class);
Log.d(TAG, "findWidgetProvider componentName=" + cn.flattenToString());
return new WidgetManagerHelper(getTargetContext())
.findProvider(cn, Process.myUserHandle());
}
});
public static LauncherAppWidgetProviderInfo findWidgetProvider(boolean hasConfigureScreen) {
LauncherAppWidgetProviderInfo info = getOnUiThread(() -> {
Instrumentation i = getInstrumentation();
ComponentName cn = new ComponentName(i.getContext(),
hasConfigureScreen ? AppWidgetWithConfig.class : AppWidgetNoConfig.class);
Log.d(TAG, "findWidgetProvider componentName=" + cn.flattenToString());
return new WidgetManagerHelper(i.getTargetContext()).findProvider(cn, myUserHandle());
});
if (info == null) {
throw new IllegalArgumentException("No valid widget provider");
}
@@ -64,7 +64,7 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest {
@Before
public void setUp() throws Exception {
super.setUp();
mWidgetInfo = TestViewHelpers.findWidgetProvider(this, true /* hasConfigureScreen */);
mWidgetInfo = TestViewHelpers.findWidgetProvider(true /* hasConfigureScreen */);
mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
}
@@ -61,7 +61,7 @@ public class AddWidgetTest extends AbstractLauncherUiTest {
waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
final LauncherAppWidgetProviderInfo widgetInfo =
TestViewHelpers.findWidgetProvider(this, false /* hasConfigureScreen */);
TestViewHelpers.findWidgetProvider(false /* hasConfigureScreen */);
WidgetResizeFrame resizeFrame = mLauncher
.getWorkspace()
@@ -17,6 +17,7 @@ package com.android.launcher3.ui.widget;
import static androidx.test.InstrumentationRegistry.getTargetContext;
import static com.android.launcher3.util.TestUtil.getOnUiThread;
import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
import static org.junit.Assert.assertEquals;
@@ -103,7 +104,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
@Test
public void testBindNormalWidget_withConfig() {
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, true);
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(true);
LauncherAppWidgetInfo item = createWidgetInfo(info, getTargetContext(), true);
addItemToScreen(item);
@@ -112,7 +113,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
@Test
public void testBindNormalWidget_withoutConfig() {
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(false);
LauncherAppWidgetInfo item = createWidgetInfo(info, getTargetContext(), true);
addItemToScreen(item);
@@ -121,7 +122,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
@Test
public void testUnboundWidget_removed() {
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(false);
LauncherAppWidgetInfo item = createWidgetInfo(info, getTargetContext(), false);
item.appWidgetId = -33;
@@ -140,7 +141,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
@Test
public void testPendingWidget_autoRestored() {
// A non-restored widget with no config screen gets restored automatically.
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(false);
// Do not bind the widget
LauncherAppWidgetInfo item = createWidgetInfo(info, getTargetContext(), false);
@@ -153,7 +154,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
@Test
public void testPendingWidget_withConfigScreen() {
// A non-restored widget with config screen get bound and shows a 'Click to setup' UI.
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, true);
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(true);
// Do not bind the widget
LauncherAppWidgetInfo item = createWidgetInfo(info, getTargetContext(), false);
@@ -18,14 +18,13 @@ package com.android.launcher3.util;
import static android.util.Base64.NO_PADDING;
import static android.util.Base64.NO_WRAP;
import static androidx.test.InstrumentationRegistry.getContext;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static androidx.test.InstrumentationRegistry.getTargetContext;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG;
import android.app.Instrumentation;
import android.app.blob.BlobHandle;
import android.app.blob.BlobStoreManager;
import android.content.Context;
@@ -35,9 +34,12 @@ import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
import android.system.OsConstants;
import android.util.Base64;
import android.util.Log;
import androidx.test.uiautomator.UiDevice;
@@ -52,27 +54,35 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
public class TestUtil {
private static final String TAG = "TestUtil";
public static final String DUMMY_PACKAGE = "com.example.android.aardwolf";
public static final int DEFAULT_USER_ID = 0;
public static final long DEFAULT_UI_TIMEOUT = 10000;
public static void installDummyApp() throws IOException {
installDummyAppForUser(DEFAULT_USER_ID);
}
public static void installDummyAppForUser(int userId) throws IOException {
Instrumentation instrumentation = getInstrumentation();
// Copy apk from resources to a local file and install from there.
final Resources resources = getContext().getResources();
final Resources resources = instrumentation.getContext().getResources();
final InputStream in = resources.openRawResource(
resources.getIdentifier("aardwolf_dummy_app",
"raw", getContext().getPackageName()));
final String apkFilename = getInstrumentation().getTargetContext().
getFilesDir().getPath() + "/dummy_app.apk";
"raw", instrumentation.getContext().getPackageName()));
final String apkFilename = instrumentation.getTargetContext()
.getFilesDir().getPath() + "/dummy_app.apk";
try (PackageInstallCheck pic = new PackageInstallCheck()) {
final FileOutputStream out = new FileOutputStream(apkFilename);
@@ -85,7 +95,7 @@ public class TestUtil {
in.close();
out.close();
final String result = UiDevice.getInstance(getInstrumentation())
final String result = UiDevice.getInstance(instrumentation)
.executeShellCommand("pm install --user " + userId + " " + apkFilename);
Assert.assertTrue(
"Failed to install wellbeing test apk; make sure the device is rooted",
@@ -177,13 +187,33 @@ public class TestUtil {
}
}
/**
* Runs the callback on the UI thread and returns the result.
*/
public static <T> T getOnUiThread(final Callable<T> callback) {
try {
FutureTask<T> task = new FutureTask<>(callback);
if (Looper.myLooper() == Looper.getMainLooper()) {
task.run();
} else {
new Handler(Looper.getMainLooper()).post(task);
}
return task.get(DEFAULT_UI_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
Log.e(TAG, "Timeout in getOnUiThread, sending SIGABRT", e);
Process.sendSignal(Process.myPid(), OsConstants.SIGABRT);
throw new RuntimeException(e);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/** Interface to indicate a runnable which can throw any exception. */
public interface UncheckedRunnable {
/** Method to run the task */
void run() throws Exception;
}
private static class PackageInstallCheck extends LauncherApps.Callback
implements AutoCloseable {
@@ -191,7 +221,8 @@ public class TestUtil {
final LauncherApps mLauncherApps;
PackageInstallCheck() {
mLauncherApps = getTargetContext().getSystemService(LauncherApps.class);
mLauncherApps = getInstrumentation().getTargetContext()
.getSystemService(LauncherApps.class);
mLauncherApps.registerCallback(this, new Handler(Looper.getMainLooper()));
}
@@ -138,17 +138,6 @@ public final class LauncherInstrumentation {
OUTSIDE_WITH_KEYCODE,
}
/**
* Represents a point in the code at which a callback can run.
*/
public enum CALLBACK_RUN_POINT {
CALLBACK_HOLD_BEFORE_DROP,
CALLBACK_HOVER_ENTER,
CALLBACK_HOVER_EXIT,
}
private Consumer<CALLBACK_RUN_POINT> mCallbackAtRunPoint = null;
// Base class for launcher containers.
abstract static class VisibleContainer {
protected final LauncherInstrumentation mLauncher;
@@ -2063,22 +2052,6 @@ public final class LauncherInstrumentation {
}
}
/**
* Sets the consumer to run callbacks at all run-points.
*/
public void setRunPointCallback(Consumer<CALLBACK_RUN_POINT> callback) {
mCallbackAtRunPoint = callback;
}
/**
* Runs the callback at the specified point if it exists.
*/
void runCallbackIfActive(CALLBACK_RUN_POINT runPoint) {
if (mCallbackAtRunPoint != null) {
mCallbackAtRunPoint.accept(runPoint);
}
}
/**
* Waits until a particular condition is true. Based on WaitMixin.
*/
@@ -15,13 +15,7 @@
*/
package com.android.launcher3.tapl;
import static com.android.launcher3.tapl.LauncherInstrumentation.CALLBACK_RUN_POINT.CALLBACK_HOVER_ENTER;
import static com.android.launcher3.tapl.LauncherInstrumentation.CALLBACK_RUN_POINT.CALLBACK_HOVER_EXIT;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
import android.view.MotionEvent;
import androidx.test.uiautomator.UiObject2;
@@ -42,28 +36,4 @@ public class OverviewTaskMenuItem {
public Rect getVisibleBounds() {
return mMenuItem.getVisibleBounds();
}
/**
* Emulate the cursor entering and exiting a hover over this menu item.
*/
public void hoverCursor() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"cursor hover entering menu item")) {
long downTime = SystemClock.uptimeMillis();
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
new Point(mMenuItem.getVisibleCenter().x, mMenuItem.getVisibleCenter().y),
null);
mLauncher.runCallbackIfActive(CALLBACK_HOVER_ENTER);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"cursor hover exiting menu item")) {
downTime = SystemClock.uptimeMillis();
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
new Point(mMenuItem.getVisibleCenter().x, mMenuItem.getVisibleCenter().y),
null);
mLauncher.runCallbackIfActive(CALLBACK_HOVER_EXIT);
}
}
}
}
@@ -18,7 +18,6 @@ package com.android.launcher3.tapl;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED;
import static com.android.launcher3.tapl.LauncherInstrumentation.CALLBACK_RUN_POINT.CALLBACK_HOLD_BEFORE_DROP;
import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -553,7 +552,6 @@ public final class Workspace extends Home {
launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating,
downTime, SystemClock.uptimeMillis(), false,
LauncherInstrumentation.GestureScope.INSIDE);
launcher.runCallbackIfActive(CALLBACK_HOLD_BEFORE_DROP);
dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
}
}
@@ -587,7 +585,6 @@ public final class Workspace extends Home {
launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating,
downTime, SystemClock.uptimeMillis(), false,
LauncherInstrumentation.GestureScope.INSIDE);
launcher.runCallbackIfActive(CALLBACK_HOLD_BEFORE_DROP);
dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
}
}