Merge "Removing UiThreadHelper and moving code to corresponding classes" into tm-qpr-dev
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 812d249..c64e9b2 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -71,7 +71,7 @@
     <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ବ୍ୟକ୍ତିଗତ ଆପ୍ ତାଲିକା"</string>
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"କାର୍ଯ୍ୟକାରୀ ଆପ୍‌ ତାଲିକା"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ବାହାର କରନ୍ତୁ"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ଅନଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ୍‌ ସୂଚନା"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java
index 1cb0752..ee1d1ff 100644
--- a/src/com/android/launcher3/util/LogConfig.java
+++ b/src/com/android/launcher3/util/LogConfig.java
@@ -45,4 +45,9 @@
      * When turned on, we enable IME related latency related logging.
      */
     public static final String IME_LATENCY_LOGGING = "ImeLatencyLogging";
+
+    /**
+     * When turned on, we enable web suggest appSearch related logging.
+     */
+    public static final String WEB_APP_SEARCH_LOGGING = "WebAppSearchLogging";
 }
diff --git a/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
new file mode 100644
index 0000000..8ce932d
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 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.celllayout;
+
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherSettings;
+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;
+
+public class FavoriteItemsTransaction {
+    private ArrayList<ItemInfo> mItemsToSubmit;
+    private Context mContext;
+    private ContentResolver mResolver;
+    public AbstractLauncherUiTest mTest;
+
+    public FavoriteItemsTransaction(Context context, AbstractLauncherUiTest test) {
+        mItemsToSubmit = new ArrayList<>();
+        mContext = context;
+        mResolver = mContext.getContentResolver();
+        mTest = test;
+    }
+
+    public FavoriteItemsTransaction addItem(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();
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
index 93fbf97..2846cae 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -47,6 +47,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
 
 
 @SmallTest
@@ -58,7 +59,7 @@
 
     private static final String TAG = ReorderWidgets.class.getSimpleName();
 
-    TestWorkspaceBuilder mBoardBuilder;
+    TestWorkspaceBuilder mWorkspaceBuilder;
 
     private View getViewAt(int cellX, int cellY) {
         return getFromLauncher(l -> l.getWorkspace().getScreenWithId(
@@ -76,7 +77,7 @@
 
     @Before
     public void setup() throws Throwable {
-        mBoardBuilder = new TestWorkspaceBuilder(this);
+        mWorkspaceBuilder = new TestWorkspaceBuilder(this, mTargetContext);
         TaplTestsLauncher3.initialize(this);
         clearHomescreen();
     }
@@ -87,7 +88,7 @@
     private boolean validateBoard(CellLayoutBoard board) {
         boolean match = true;
         Point cellDimensions = getCellDimensions();
-        for (CellLayoutBoard.WidgetRect widgetRect: board.getWidgets()) {
+        for (CellLayoutBoard.WidgetRect widgetRect : board.getWidgets()) {
             if (widgetRect.shouldIgnore()) {
                 continue;
             }
@@ -108,10 +109,13 @@
         return match;
     }
 
-    private void runTestCase(ReorderTestCase testCase) {
+    private void runTestCase(ReorderTestCase testCase)
+            throws ExecutionException, InterruptedException {
         Point mainWidgetCellPos = testCase.mStart.getMain();
 
-        mBoardBuilder.buildBoard(testCase.mStart);
+        FavoriteItemsTransaction transaction =
+                new FavoriteItemsTransaction(mTargetContext, this);
+        mWorkspaceBuilder.buildFromBoard(testCase.mStart, transaction).commit();
 
         Widget widget = mLauncher.getWorkspace().getWidgetAtCell(mainWidgetCellPos.x,
                 mainWidgetCellPos.y);
@@ -132,7 +136,8 @@
      *
      * @param testCaseMap map containing all the tests per grid size (Point)
      */
-    private void runTestCaseMap(Map<Point, ReorderTestCase> testCaseMap, String testName) {
+    private void runTestCaseMap(Map<Point, ReorderTestCase> testCaseMap, String testName)
+            throws ExecutionException, InterruptedException {
         Point iconGridDimensions = mLauncher.getWorkspace().getIconGridDimensions();
         Log.d(TAG, "Running test " + testName + " for grid " + iconGridDimensions);
         Assume.assumeTrue(
@@ -143,26 +148,26 @@
 
     @ScreenRecord // b/242323136
     @Test
-    public void simpleReorder() {
+    public void simpleReorder()  throws ExecutionException, InterruptedException {
         runTestCaseMap(SimpleReorderCase.TEST_BY_GRID_SIZE,
                 SimpleReorderCase.class.getSimpleName());
     }
 
     @ScreenRecord // b/242323136
     @Test
-    public void pushTest() {
+    public void pushTest()  throws ExecutionException, InterruptedException {
         runTestCaseMap(PushReorderCase.TEST_BY_GRID_SIZE, PushReorderCase.class.getSimpleName());
     }
 
     @ScreenRecord // b/242323136
     @Test
-    public void fullReorder() {
+    public void fullReorder()  throws ExecutionException, InterruptedException {
         runTestCaseMap(FullReorderCase.TEST_BY_GRID_SIZE, FullReorderCase.class.getSimpleName());
     }
 
     @ScreenRecord // b/242323136
     @Test
-    public void moveOutReorder() {
+    public void moveOutReorder()  throws ExecutionException, InterruptedException {
         runTestCaseMap(MoveOutReorderCase.TEST_BY_GRID_SIZE,
                 MoveOutReorderCase.class.getSimpleName());
     }
diff --git a/tests/src/com/android/launcher3/celllayout/TestWorkspaceBuilder.java b/tests/src/com/android/launcher3/celllayout/TestWorkspaceBuilder.java
index 10e399d..16448af 100644
--- a/tests/src/com/android/launcher3/celllayout/TestWorkspaceBuilder.java
+++ b/tests/src/com/android/launcher3/celllayout/TestWorkspaceBuilder.java
@@ -15,9 +15,12 @@
  */
 package com.android.launcher3.celllayout;
 
+import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
 import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
 
 import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
 import android.graphics.Rect;
 import android.os.Process;
 import android.os.UserHandle;
@@ -25,8 +28,10 @@
 
 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;
@@ -35,6 +40,7 @@
 
 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");
 
@@ -42,69 +48,118 @@
 
     private UserHandle mMyUser;
 
-    public TestWorkspaceBuilder(AbstractLauncherUiTest test) {
+    private Context mContext;
+    private ContentResolver mResolver;
+
+    public TestWorkspaceBuilder(AbstractLauncherUiTest test, Context context) {
         mTest = test;
         mMyUser = Process.myUserHandle();
+        mContext = context;
+        mResolver = mContext.getContentResolver();
     }
 
-    private static final String TAG = "CellLayoutBoardBuilder";
-
     /**
      * Fills the given rect in WidgetRect with 1x1 widgets. This is useful to equalize cases.
      */
-    private void fillWithWidgets(CellLayoutBoard.WidgetRect widgetRect) {
+    private FavoriteItemsTransaction fillWithWidgets(CellLayoutBoard.WidgetRect widgetRect,
+            FavoriteItemsTransaction transaction) {
         int initX = widgetRect.getCellX();
         int initY = widgetRect.getCellY();
         for (int x = initX; x < initX + widgetRect.getSpanX(); x++) {
             for (int y = initY; y < initY + widgetRect.getSpanY(); y++) {
                 try {
                     // this widgets are filling, we don't care if we can't place them
-                    addWidgetInCell(
+                    ItemInfo item = createWidgetInCell(
                             new CellLayoutBoard.WidgetRect(CellLayoutBoard.CellType.IGNORE,
                                     new Rect(x, y, x, y))
                     );
+                    transaction.addItem(item);
                 } catch (Exception e) {
                     Log.d(TAG, "Unable to place filling widget at " + x + "," + y);
                 }
             }
         }
+        return transaction;
     }
 
-    private void addWidgetInCell(CellLayoutBoard.WidgetRect widgetRect) {
+    private int getID() {
+        return LauncherSettings.Settings.call(
+                        mResolver, LauncherSettings.Settings.METHOD_NEW_ITEM_ID)
+                .getInt(LauncherSettings.Settings.EXTRA_VALUE);
+    }
+
+    private AppInfo getApp() {
+        return new AppInfo(APP_COMPONENT_NAME, "test icon", mMyUser,
+                AppInfo.makeLaunchIntent(APP_COMPONENT_NAME));
+    }
+
+    private void addCorrespondingWidgetRect(CellLayoutBoard.WidgetRect widgetRect,
+            FavoriteItemsTransaction transaction) {
+        if (widgetRect.mType == 'x') {
+            fillWithWidgets(widgetRect, transaction);
+        } else {
+            transaction.addItem(createWidgetInCell(widgetRect));
+        }
+    }
+
+    /**
+     * Builds the given board into the transaction
+     */
+    public FavoriteItemsTransaction buildFromBoard(CellLayoutBoard board,
+            FavoriteItemsTransaction transaction) {
+        board.getWidgets().forEach(
+                (widgetRect) -> addCorrespondingWidgetRect(widgetRect, transaction));
+        board.getIcons().forEach((iconPoint) ->
+                transaction.addItem(createIconInCell(iconPoint))
+        );
+        return transaction;
+    }
+
+    /**
+     * Fills the hotseat row with apps instead of suggestions, for this to work the workspace should
+     * be clean otherwise this doesn't overrides the existing icons.
+     */
+    public FavoriteItemsTransaction fillHotseatIcons(FavoriteItemsTransaction transaction) {
+        int hotseatCount = InvariantDeviceProfile.INSTANCE.get(mContext).numShownHotseatIcons;
+        for (int i = 0; i < hotseatCount; i++) {
+            transaction.addItem(getHotseatValues(i));
+        }
+        return transaction;
+    }
+
+    private ItemInfo createWidgetInCell(CellLayoutBoard.WidgetRect widgetRect) {
         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();
-        mTest.addItemToScreen(item);
+        item.screenId = FIRST_SCREEN_ID;
+        return item;
     }
 
-    private void addIconInCell(CellLayoutBoard.IconPoint iconPoint) {
-        AppInfo appInfo = new AppInfo(APP_COMPONENT_NAME, "test icon", mMyUser,
-                AppInfo.makeLaunchIntent(APP_COMPONENT_NAME));
-
-        appInfo.cellX = iconPoint.getCoord().x;
-        appInfo.cellY = iconPoint.getCoord().y;
-        appInfo.minSpanY = appInfo.minSpanX = appInfo.spanX = appInfo.spanY = 1;
-        appInfo.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
-        appInfo.componentName = APP_COMPONENT_NAME;
-
-        mTest.addItemToScreen(new WorkspaceItemInfo(appInfo));
+    private ItemInfo createIconInCell(CellLayoutBoard.IconPoint iconPoint) {
+        WorkspaceItemInfo item = new WorkspaceItemInfo(getApp());
+        item.id = getID();
+        item.screenId = FIRST_SCREEN_ID;
+        item.cellX = iconPoint.getCoord().x;
+        item.cellY = iconPoint.getCoord().y;
+        item.minSpanY = item.minSpanX = item.spanX = item.spanY = 1;
+        item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
+        return item;
     }
 
-    private void addCorrespondingWidgetRect(CellLayoutBoard.WidgetRect widgetRect) {
-        if (widgetRect.mType == 'x') {
-            fillWithWidgets(widgetRect);
-        } else {
-            addWidgetInCell(widgetRect);
-        }
-    }
-
-    public void buildBoard(CellLayoutBoard board) {
-        board.getWidgets().forEach(this::addCorrespondingWidgetRect);
-        board.getIcons().forEach(this::addIconInCell);
+    private ItemInfo getHotseatValues(int x) {
+        WorkspaceItemInfo item = new WorkspaceItemInfo(getApp());
+        item.id = getID();
+        item.cellX = x;
+        item.cellY = 0;
+        item.minSpanY = item.minSpanX = item.spanX = item.spanY = 1;
+        item.rank = x;
+        item.screenId = x;
+        item.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+        return item;
     }
 }
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
index 94e55cf..a98882c 100644
--- a/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
+++ b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
@@ -31,13 +31,13 @@
             + "xxxxx\n"
             + "222mm\n"
             + "222mm\n"
-            + "ad111\n"
-            + "bc111";
+            + "ii111\n"
+            + "ii111";
     private static final Point MOVE_TO_5x5 = new Point(0, 4);
     private static final String END_BOARD_STR_5x5 = ""
             + "xxxxx\n"
-            + "222ad\n"
-            + "222bc\n"
+            + "222ii\n"
+            + "222ii\n"
             + "mm111\n"
             + "mm111";
     private static final ReorderTestCase TEST_CASE_5x5 = new ReorderTestCase(START_BOARD_STR_5x5,
@@ -50,13 +50,13 @@
             + "xxxxxx\n"
             + "2222mm\n"
             + "2222mm\n"
-            + "ad1111\n"
-            + "bc1111";
+            + "ii1111\n"
+            + "ii1111";
     private static final Point MOVE_TO_6x5 = new Point(0, 4);
     private static final String END_BOARD_STR_6x5 = ""
             + "xxxxxx\n"
-            + "2222ad\n"
-            + "2222bc\n"
+            + "2222ii\n"
+            + "2222ii\n"
             + "mm1111\n"
             + "mm1111";
     private static final ReorderTestCase TEST_CASE_6x5 = new ReorderTestCase(START_BOARD_STR_6x5,
@@ -68,13 +68,13 @@
     private static final String START_BOARD_STR_4x4 = ""
             + "xxxx\n"
             + "22mm\n"
-            + "admm\n"
-            + "bc11";
+            + "iimm\n"
+            + "ii11";
     private static final Point MOVE_TO_4x4 = new Point(0, 3);
     private static final String END_BOARD_STR_4x4 = ""
             + "xxxx\n"
-            + "22ad\n"
-            + "mmbc\n"
+            + "22ii\n"
+            + "mmii\n"
             + "mm11";
 
     private static final ReorderTestCase TEST_CASE_4x4 = new ReorderTestCase(START_BOARD_STR_4x4,