Merge "Creating a new dismiss animation while one is pending is now valid" into ub-launcher3-master
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 85eed1f..02af0d6 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -29,7 +29,6 @@
 import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ROTATION;
-
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
@@ -44,7 +43,8 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.view.View;
-
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
@@ -77,9 +77,6 @@
 import java.util.function.BiPredicate;
 import java.util.function.Consumer;
 
-import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-
 /**
  * Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
  */
@@ -156,10 +153,21 @@
         public void onQuickInteractionStart(Launcher activity, RunningTaskInfo taskInfo,
                 boolean activityVisible, TouchInteractionLog touchInteractionLog) {
             LauncherState fromState = activity.getStateManager().getState();
-            activity.getStateManager().goToState(FAST_OVERVIEW, activityVisible);
-
             QuickScrubController controller = activity.<RecentsView>getOverviewPanel()
                     .getQuickScrubController();
+            boolean isQuickSwitch = controller.isQuickSwitch();
+            boolean animate = activityVisible;
+            if (isQuickSwitch && fromState == FAST_OVERVIEW && !animate) {
+                // We can already be in FAST_OVERVIEW if createActivityController() was called
+                // before us. This could happen, for instance, when launcher is slow to load when
+                // starting quick switch, causing us to call onQuickScrubStart() on the background
+                // thread. In this case, we also hadn't set isQuickSwitch = true before setting
+                // FAST_OVERVIEW, so we need to reapply FAST_OVERVIEW to take that into account.
+                activity.getStateManager().reapplyState();
+            } else {
+                activity.getStateManager().goToState(FAST_OVERVIEW, animate);
+            }
+
             controller.onQuickScrubStart(activityVisible && !fromState.overviewUi, this,
                     touchInteractionLog);
 
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index a604da0..b0d7ff3 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -27,7 +27,6 @@
 import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
 import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -50,7 +49,9 @@
 import android.view.ViewTreeObserver.OnDrawListener;
 import android.view.WindowManager;
 import android.view.animation.Interpolator;
-
+import androidx.annotation.AnyThread;
+import androidx.annotation.UiThread;
+import androidx.annotation.WorkerThread;
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
@@ -90,10 +91,6 @@
 import java.util.StringJoiner;
 import java.util.function.BiFunction;
 
-import androidx.annotation.AnyThread;
-import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
-
 @TargetApi(Build.VERSION_CODES.O)
 public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
     private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
@@ -143,6 +140,9 @@
             STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_STARTED
                     | STATE_APP_CONTROLLER_RECEIVED | STATE_SCREENSHOT_CAPTURED;
 
+    private static final int QUICK_SCRUB_START_UI_STATE = STATE_LAUNCHER_STARTED
+            | STATE_QUICK_SCRUB_START | STATE_APP_CONTROLLER_RECEIVED;
+
     // For debugging, keep in sync with above states
     private static final String[] STATES = new String[] {
             "STATE_LAUNCHER_PRESENT",
@@ -325,8 +325,7 @@
                 | STATE_SCALED_CONTROLLER_APP,
                 this::notifyTransitionCancelled);
 
-        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START
-                        | STATE_APP_CONTROLLER_RECEIVED, this::onQuickScrubStartUi);
+        mStateCallback.addCallback(QUICK_SCRUB_START_UI_STATE, this::onQuickScrubStartUi);
         mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START
                 | STATE_SCALED_CONTROLLER_RECENTS, this::onFinishedTransitionToQuickScrub);
         mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_CURRENT_TASK_FINISHED
@@ -1026,7 +1025,7 @@
     public void onQuickScrubProgress(float progress) {
         mCurrentQuickScrubProgress = progress;
         if (Looper.myLooper() != Looper.getMainLooper() || mQuickScrubController == null
-                || mQuickScrubBlocked) {
+                || mQuickScrubBlocked || !mStateCallback.hasStates(QUICK_SCRUB_START_UI_STATE)) {
             return;
         }
         mQuickScrubController.onQuickScrubProgress(progress);
diff --git a/robolectric_tests/Android.mk b/robolectric_tests/Android.mk
index 5011764..a57b97a 100644
--- a/robolectric_tests/Android.mk
+++ b/robolectric_tests/Android.mk
@@ -29,6 +29,8 @@
 LOCAL_JAVA_LIBRARIES := \
     platform-robolectric-3.6.1-prebuilt
 
+LOCAL_JAVA_RESOURCE_DIRS := resources config
+
 LOCAL_INSTRUMENTATION_FOR := Launcher3
 LOCAL_MODULE_TAGS := optional
 
diff --git a/robolectric_tests/config/robolectric.properties b/robolectric_tests/config/robolectric.properties
new file mode 100644
index 0000000..782b8cb
--- /dev/null
+++ b/robolectric_tests/config/robolectric.properties
@@ -0,0 +1,2 @@
+manifest=packages/apps/Launcher3/AndroidManifest.xml
+sdk=28
\ No newline at end of file
diff --git a/tests/res/raw/cache_data_updated_task_data.txt b/robolectric_tests/resources/cache_data_updated_task_data.txt
similarity index 100%
rename from tests/res/raw/cache_data_updated_task_data.txt
rename to robolectric_tests/resources/cache_data_updated_task_data.txt
diff --git a/tests/res/raw/package_install_state_change_task_data.txt b/robolectric_tests/resources/package_install_state_change_task_data.txt
similarity index 100%
rename from tests/res/raw/package_install_state_change_task_data.txt
rename to robolectric_tests/resources/package_install_state_change_task_data.txt
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
similarity index 95%
rename from tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
rename to robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
index 6673ba9..fd31033 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
@@ -15,9 +15,6 @@
 import android.net.Uri;
 import android.util.Pair;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherProvider;
 import com.android.launcher3.LauncherSettings;
@@ -30,6 +27,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.robolectric.RobolectricTestRunner;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -37,8 +35,7 @@
 /**
  * Tests for {@link AddWorkspaceItemsTask}
  */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
 public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase {
 
     private final ComponentName mComponent1 = new ComponentName("a", "b");
@@ -174,7 +171,7 @@
     }
 
     private void commitScreensToDb() throws Exception {
-        LauncherSettings.Settings.call(mProviderRule.getResolver(),
+        LauncherSettings.Settings.call(targetContext.getContentResolver(),
                 LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
 
         Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
@@ -189,6 +186,6 @@
             v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
             ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());
         }
-        mProviderRule.getResolver().applyBatch(LauncherProvider.AUTHORITY, ops);
+        targetContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, ops);
     }
 }
diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
similarity index 88%
rename from tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
rename to robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index afe9dc6..92d065e 100644
--- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -7,24 +7,17 @@
 import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Color;
 import android.os.Process;
 import android.os.UserHandle;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.rule.provider.ProviderTestRule;
 
 import com.android.launcher3.AllAppsList;
 import com.android.launcher3.AppFilter;
 import com.android.launcher3.AppInfo;
-import com.android.launcher3.icons.cache.CachingLogic;
-import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherAppState;
@@ -33,13 +26,18 @@
 import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherProvider;
 import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.icons.cache.CachingLogic;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.Provider;
 import com.android.launcher3.util.TestLauncherProvider;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.mockito.ArgumentCaptor;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowContentResolver;
+import org.robolectric.shadows.ShadowLog;
 
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
@@ -55,12 +53,8 @@
  */
 public class BaseModelUpdateTaskTestCase {
 
-    @Rule
-    public ProviderTestRule mProviderRule =
-            new ProviderTestRule.Builder(TestLauncherProvider.class, LauncherProvider.AUTHORITY)
-                    .build();
-
     public final HashMap<Class, HashMap<String, Field>> fieldCache = new HashMap<>();
+    private TestLauncherProvider mProvider;
 
     public Context targetContext;
     public UserHandle myUser;
@@ -77,6 +71,11 @@
 
     @Before
     public void setUp() throws Exception {
+        ShadowLog.stream = System.out;
+
+        mProvider = Robolectric.setupContentProvider(TestLauncherProvider.class);
+        ShadowContentResolver.registerProviderInternal(LauncherProvider.AUTHORITY, mProvider);
+
         callbacks = mock(Callbacks.class);
         appState = mock(LauncherAppState.class);
         model = mock(LauncherModel.class);
@@ -89,12 +88,8 @@
         myUser = Process.myUserHandle();
 
         bgDataModel = new BgDataModel();
-        targetContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
-            @Override
-            public ContentResolver getContentResolver() {
-                return mProviderRule.getResolver();
-            }
-        };
+        targetContext = RuntimeEnvironment.application;
+
         idp = new InvariantDeviceProfile();
         iconCache = new MyIconCache(targetContext, idp);
 
@@ -103,7 +98,6 @@
         when(appState.getIconCache()).thenReturn(iconCache);
         when(appState.getInvariantDeviceProfile()).thenReturn(idp);
         when(appState.getContext()).thenReturn(targetContext);
-
     }
 
     /**
@@ -126,11 +120,8 @@
      * Initializes mock data for the test.
      */
     public void initializeData(String resourceName) throws Exception {
-        Context myContext = InstrumentationRegistry.getContext();
-        Resources res = myContext.getResources();
-        int id = res.getIdentifier(resourceName, "raw", myContext.getPackageName());
-        try (BufferedReader reader =
-                     new BufferedReader(new InputStreamReader(res.openRawResource(id)))) {
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(
+                this.getClass().getResourceAsStream(resourceName)))) {
             String line;
             HashMap<String, Class> classMap = new HashMap<>();
             while((line = reader.readLine()) != null) {
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
similarity index 94%
rename from tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
rename to robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 5fe9018..f17eac7 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -6,9 +6,6 @@
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.ShortcutInfo;
@@ -16,6 +13,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
 
 import java.util.Arrays;
 import java.util.HashSet;
@@ -23,15 +21,14 @@
 /**
  * Tests for {@link CacheDataUpdatedTask}
  */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
 public class CacheDataUpdatedTaskTest extends BaseModelUpdateTaskTestCase {
 
     private static final String NEW_LABEL_PREFIX = "new-label-";
 
     @Before
     public void initData() throws Exception {
-        initializeData("cache_data_updated_task_data");
+        initializeData("/cache_data_updated_task_data.txt");
         // Add dummy entries in the cache to simulate update
         for (ItemInfo info : bgDataModel.itemsIdMap) {
             iconCache.addCache(info.getTargetComponent(), NEW_LABEL_PREFIX + info.id);
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
similarity index 89%
rename from tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
rename to robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
index 7fa401b..67580dd 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
@@ -1,21 +1,20 @@
 package com.android.launcher3.model;
 
-import android.content.ContentResolver;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
 import android.database.Cursor;
 import android.graphics.Point;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.rule.provider.ProviderTestRule;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherProvider;
 import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.config.FlagOverrideRule;
+import com.android.launcher3.config.FlagOverrideRule.FlagOverride;
 import com.android.launcher3.model.GridSizeMigrationTask.MultiStepMigrationTask;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.TestLauncherProvider;
@@ -24,25 +23,20 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowContentResolver;
 
 import java.util.HashSet;
 import java.util.LinkedList;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
 /**
  * Unit tests for {@link GridSizeMigrationTask}
  */
-@MediumTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
 public class GridSizeMigrationTaskTest {
 
-    @Rule
-    public ProviderTestRule mProviderRule =
-            new ProviderTestRule.Builder(TestLauncherProvider.class, LauncherProvider.AUTHORITY)
-                    .build();
-
     private static final int DESKTOP = LauncherSettings.Favorites.CONTAINER_DESKTOP;
     private static final int HOTSEAT = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
 
@@ -50,27 +44,25 @@
     private static final int SHORTCUT = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
 
     private static final String TEST_PACKAGE = "com.android.launcher3.validpackage";
-    private static final String VALID_INTENT =
-            new Intent(Intent.ACTION_MAIN).setPackage(TEST_PACKAGE).toUri(0);
+
+    @Rule
+    public final FlagOverrideRule flags = new FlagOverrideRule();
 
     private HashSet<String> mValidPackages;
     private InvariantDeviceProfile mIdp;
     private Context mContext;
+    private TestLauncherProvider mProvider;
 
     @Before
-    public void setUp() throws Exception {
+    public void setUp() {
+
         mValidPackages = new HashSet<>();
         mValidPackages.add(TEST_PACKAGE);
-
         mIdp = new InvariantDeviceProfile();
+        mContext = RuntimeEnvironment.application;
 
-        mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
-
-            @Override
-            public ContentResolver getContentResolver() {
-                return mProviderRule.getResolver();
-            }
-        };
+        mProvider = Robolectric.setupContentProvider(TestLauncherProvider.class);
+        ShadowContentResolver.registerProviderInternal(LauncherProvider.AUTHORITY, mProvider);
     }
 
     @Test
@@ -112,7 +104,7 @@
         int total = 0;
 
         for (int id : sortedIds) {
-            Cursor c = mProviderRule.getResolver().query(LauncherSettings.Favorites.CONTENT_URI,
+            Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
                     new String[]{LauncherSettings.Favorites._ID},
                     "container=-101 and screen=" + screenId, null, null, null);
 
@@ -130,7 +122,7 @@
         }
 
         // Verify that not other entry exist in the DB.
-        Cursor c = mProviderRule.getResolver().query(LauncherSettings.Favorites.CONTENT_URI,
+        Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
                 new String[]{LauncherSettings.Favorites._ID},
                 "container=-101", null, null, null);
         assertEquals(total, c.getCount());
@@ -240,6 +232,7 @@
         }});
     }
 
+    @FlagOverride(key = "QSB_ON_FIRST_SCREEN", value = true)
     @Test
     public void testWorkspace_first_row_blocked() throws Exception {
         // The first screen has one item on the 4th column which needs moving, as the first row
@@ -265,6 +258,7 @@
         }});
     }
 
+    @FlagOverride(key = "QSB_ON_FIRST_SCREEN", value = true)
     @Test
     public void testWorkspace_items_moved_to_empty_first_row() throws Exception {
         // Items will get moved to the next screen to keep the first screen empty.
@@ -301,7 +295,7 @@
      * @return the same grid representation where each entry is the corresponding item id.
      */
     private int[][][] createGrid(int[][][] typeArray, int startScreen) throws Exception {
-        LauncherSettings.Settings.call(mProviderRule.getResolver(),
+        LauncherSettings.Settings.call(mContext.getContentResolver(),
                 LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
         int[][][] ids = new int[typeArray.length][][];
 
@@ -310,13 +304,13 @@
             int screenId = startScreen + i;
 
             // Keep the screen id counter up to date
-            LauncherSettings.Settings.call(mProviderRule.getResolver(),
+            LauncherSettings.Settings.call(mContext.getContentResolver(),
                     LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
 
             ContentValues v = new ContentValues();
             v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
             v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
-            mProviderRule.getResolver().insert(LauncherSettings.WorkspaceScreens.CONTENT_URI, v);
+            mContext.getContentResolver().insert(LauncherSettings.WorkspaceScreens.CONTENT_URI, v);
 
             ids[i] = new int[typeArray[i].length][];
             for (int y = 0; y < typeArray[i].length; y++) {
@@ -331,6 +325,8 @@
                 }
             }
         }
+
+        IntArray allScreens = LauncherModel.loadWorkspaceScreensDb(mContext);
         return ids;
     }
 
@@ -350,7 +346,7 @@
                 for (int x = 0; x < ids[i][y].length; x++) {
                     int id = ids[i][y][x];
 
-                    Cursor c = mProviderRule.getResolver().query(
+                    Cursor c = mContext.getContentResolver().query(
                             LauncherSettings.Favorites.CONTENT_URI,
                             new String[]{LauncherSettings.Favorites._ID},
                             "container=-100 and screen=" + screenId +
@@ -370,7 +366,7 @@
         }
 
         // Verify that not other entry exist in the DB.
-        Cursor c = mProviderRule.getResolver().query(LauncherSettings.Favorites.CONTENT_URI,
+        Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
                 new String[]{LauncherSettings.Favorites._ID},
                 "container=-100", null, null, null);
         assertEquals(total, c.getCount());
@@ -383,7 +379,7 @@
      *             folder (where the type represents the number of items in the folder).
      */
     private int addItem(int type, int screen, int container, int x, int y) throws Exception {
-        int id = LauncherSettings.Settings.call(mProviderRule.getResolver(),
+        int id = LauncherSettings.Settings.call(mContext.getContentResolver(),
                 LauncherSettings.Settings.METHOD_NEW_ITEM_ID)
                 .getInt(LauncherSettings.Settings.EXTRA_VALUE);
 
@@ -398,7 +394,8 @@
 
         if (type == APPLICATION || type == SHORTCUT) {
             values.put(LauncherSettings.Favorites.ITEM_TYPE, type);
-            values.put(LauncherSettings.Favorites.INTENT, VALID_INTENT);
+            values.put(LauncherSettings.Favorites.INTENT,
+                    new Intent(Intent.ACTION_MAIN).setPackage(TEST_PACKAGE).toUri(0));
         } else {
             values.put(LauncherSettings.Favorites.ITEM_TYPE,
                     LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
@@ -408,7 +405,7 @@
             }
         }
 
-        mProviderRule.getResolver().insert(LauncherSettings.Favorites.CONTENT_URI, values);
+        mContext.getContentResolver().insert(LauncherSettings.Favorites.CONTENT_URI, values);
         return id;
     }
 
diff --git a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
similarity index 91%
rename from tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
rename to robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
index 25100dc..c7b4613 100644
--- a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
@@ -2,9 +2,6 @@
 
 import static org.junit.Assert.assertEquals;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.ShortcutInfo;
@@ -14,6 +11,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
 
 import java.util.Arrays;
 import java.util.HashSet;
@@ -21,13 +19,12 @@
 /**
  * Tests for {@link PackageInstallStateChangedTask}
  */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
 public class PackageInstallStateChangedTaskTest extends BaseModelUpdateTaskTestCase {
 
     @Before
     public void initData() throws Exception {
-        initializeData("package_install_state_change_task_data");
+        initializeData("/package_install_state_change_task_data.txt");
     }
 
     private PackageInstallStateChangedTask newTask(String pkg, int progress) {
diff --git a/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java b/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
index faec380..8513353 100644
--- a/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
+++ b/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
@@ -21,7 +21,6 @@
 import org.junit.runner.RunWith;
 
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -31,7 +30,6 @@
  * Robolectric unit tests for {@link IntSet}
  */
 @RunWith(RobolectricTestRunner.class)
-@Config(sdk = 26)
 public class IntSetTest {
 
     @Test
diff --git a/tests/src/com/android/launcher3/util/TestLauncherProvider.java b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
similarity index 90%
rename from tests/src/com/android/launcher3/util/TestLauncherProvider.java
rename to robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
index 1d6c18b..32808f5 100644
--- a/tests/src/com/android/launcher3/util/TestLauncherProvider.java
+++ b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
@@ -23,11 +23,6 @@
         }
     }
 
-    public SQLiteOpenHelper getHelper() {
-        createDbIfNotExists();
-        return mOpenHelper;
-    }
-
     @Override
     protected void notifyListeners() { }
 
@@ -48,4 +43,4 @@
         @Override
         protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index b3dabae..a5f97de 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -96,10 +96,12 @@
     @Thunk boolean mIsLoaderTaskRunning;
 
     @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
+    private static final Looper mWorkerLooper;
     static {
         sWorkerThread.start();
+        mWorkerLooper = sWorkerThread.getLooper();
     }
-    @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());
+    @Thunk static final Handler sWorker = new Handler(mWorkerLooper);
 
     // Indicates whether the current model data is valid or not.
     // We start off with everything not loaded. After that, we assume that
@@ -708,7 +710,7 @@
      * @return the looper for the worker thread which can be used to start background tasks.
      */
     public static Looper getWorkerLooper() {
-        return sWorkerThread.getLooper();
+        return mWorkerLooper;
     }
 
     public static void setWorkerPriority(final int priority) {