Load folder names during LoaderTask

Bug: 147359653

Change-Id: I4d1b53c3a72d0773d4bc8819ee8118fc719944ad
diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java
index 763432d..a32fd12 100644
--- a/src/com/android/launcher3/DropTarget.java
+++ b/src/com/android/launcher3/DropTarget.java
@@ -16,11 +16,14 @@
 
 package com.android.launcher3;
 
+import android.content.Context;
 import android.graphics.Rect;
 
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.folder.FolderNameProvider;
 
 /**
  * Interface defining an object that can receive a drag.
@@ -67,7 +70,12 @@
 
         public DragViewStateAnnouncer stateAnnouncer;
 
-        public DragObject() {
+        public FolderNameProvider folderNameProvider;
+
+        public DragObject(Context context) {
+            if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
+                folderNameProvider = FolderNameProvider.newInstance(context);
+            }
         }
 
         /**
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 0fea0dc..787eee1 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import android.content.Intent;
 import android.os.Process;
 
 import com.android.launcher3.model.ModelWriter;
@@ -49,6 +50,8 @@
 
     public int options;
 
+    public Intent suggestedFolderNames;
+
     /**
      * The apps and shortcuts
      */
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2ccdd6f..fe987bc 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -103,7 +103,6 @@
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.folder.FolderGridOrganizer;
 import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.folder.FolderNameProvider;
 import com.android.launcher3.graphics.RotationMode;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.keyboard.CustomActionsPopup;
@@ -616,10 +615,6 @@
         return mStateManager;
     }
 
-    public FolderNameProvider getFolderNameProvider() {
-        return new FolderNameProvider();
-    }
-
     @Override
     public <T extends View> T findViewById(int id) {
         return mLauncherView.findViewById(id);
@@ -1259,13 +1254,13 @@
                 cellXY[1] = cellY;
                 foundCellSpan = true;
 
+                DragObject dragObject = new DragObject(getApplicationContext());
+                dragObject.dragInfo = info;
                 // If appropriate, either create a folder or add to an existing folder
                 if (mWorkspace.createUserFolderIfNecessary(view, container, layout, cellXY, 0,
-                        true, null)) {
+                        true, dragObject)) {
                     return;
                 }
-                DragObject dragObject = new DragObject();
-                dragObject.dragInfo = info;
                 if (mWorkspace.addToExistingFolderIfNecessary(view, layout, cellXY, 0, dragObject,
                         true)) {
                     return;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 670363e..beaafda 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1673,7 +1673,7 @@
     }
 
     boolean createUserFolderIfNecessary(View newView, int container, CellLayout target,
-            int[] targetCell, float distance, boolean external, DragView dragView) {
+            int[] targetCell, float distance, boolean external, DragObject d) {
         if (distance > mMaxDistanceForFolderCreation) return false;
         View v = target.getChildAt(targetCell[0], targetCell[1]);
 
@@ -1711,14 +1711,13 @@
             sourceInfo.cellY = -1;
 
             // If the dragView is null, we can't animate
-            boolean animate = dragView != null;
+            boolean animate = d != null;
             if (animate) {
                 // In order to keep everything continuous, we hand off the currently rendered
                 // folder background to the newly created icon. This preserves animation state.
                 fi.setFolderBackground(mFolderCreateBg);
                 mFolderCreateBg = new PreviewBackground();
-                fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale
-                );
+                fi.performCreateAnimation(destInfo, v, sourceInfo, d, folderLocation, scale);
             } else {
                 fi.prepareCreateAnimation(v);
                 fi.addItem(destInfo);
@@ -1799,8 +1798,8 @@
                 // If the item being dropped is a shortcut and the nearest drop
                 // cell also contains a shortcut, then create a folder with the two shortcuts.
                 if (createUserFolderIfNecessary(cell, container,
-                        dropTargetLayout, mTargetCell, distance, false, d.dragView) ||
-                        addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
+                        dropTargetLayout, mTargetCell, distance, false, d)
+                        || addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
                                 distance, d, false)) {
                     mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
                     return;
@@ -2561,7 +2560,7 @@
                 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
                         mDragViewVisualCenter[1], mTargetCell);
                 if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,
-                        true, d.dragView)) {
+                        true, d)) {
                     return;
                 }
                 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 8adec27..54a44ee 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -28,7 +28,6 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.IBinder;
-import android.util.Log;
 import android.view.DragEvent;
 import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
@@ -43,7 +42,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.WorkspaceItemInfo;
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
-import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.TouchController;
@@ -174,7 +172,7 @@
 
         mLastDropTarget = null;
 
-        mDragObject = new DropTarget.DragObject();
+        mDragObject = new DropTarget.DragObject(mLauncher.getApplicationContext());
 
         mIsInPreDrag = mOptions.preDragCondition != null
                 && !mOptions.preDragCondition.shouldStartDrag(0);
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 90d8125..024c7dd 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -26,6 +26,7 @@
 import android.annotation.SuppressLint;
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.Canvas;
 import android.graphics.Path;
 import android.graphics.Rect;
@@ -300,9 +301,8 @@
         post(() -> {
             if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
                 if (TextUtils.isEmpty(mFolderName.getText())) {
-                    final String[] suggestedNames = new String[FolderNameProvider.SUGGEST_MAX];
-                    mLauncher.getFolderNameProvider().getSuggestedFolderName(getContext(),
-                            mInfo.contents, suggestedNames);
+                    String[] suggestedNames =
+                            mInfo.suggestedFolderNames.getStringArrayExtra("suggest");
                     mFolderName.setText(suggestedNames[0]);
                     mFolderName.displayCompletions(Arrays.asList(suggestedNames).subList(1,
                             suggestedNames.length));
@@ -446,17 +446,19 @@
      * Show suggested folder title.
      */
     public void showSuggestedTitle(String[] suggestName) {
-        if (FeatureFlags.FOLDER_NAME_SUGGEST.get()
-                && TextUtils.isEmpty(mFolderName.getText().toString())
-                && !mInfo.hasOption(FolderInfo.FLAG_MANUAL_FOLDER_NAME)) {
-            if (suggestName.length > 0 && !TextUtils.isEmpty(suggestName[0])) {
-                mFolderName.setHint("");
-                mFolderName.setText(suggestName[0]);
-                mInfo.title = suggestName[0];
-                animateOpen(mInfo.contents, 0, true);
-                mFolderName.showKeyboard();
-                mFolderName.displayCompletions(
-                        Arrays.asList(suggestName).subList(1, suggestName.length));
+        if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
+            mInfo.suggestedFolderNames = new Intent().putExtra("suggest", suggestName);
+            if (TextUtils.isEmpty(mFolderName.getText().toString())
+                    && !mInfo.hasOption(FolderInfo.FLAG_MANUAL_FOLDER_NAME)) {
+                if (suggestName.length > 0 && !TextUtils.isEmpty(suggestName[0])) {
+                    mFolderName.setHint("");
+                    mFolderName.setText(suggestName[0]);
+                    mInfo.title = suggestName[0];
+                    animateOpen(mInfo.contents, 0, true);
+                    mFolderName.showKeyboard();
+                    mFolderName.displayCompletions(
+                            Arrays.asList(suggestName).subList(1, suggestName.length));
+                }
             }
         }
     }
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 8c56823..6a47b98 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -288,8 +288,9 @@
     }
 
     public void performCreateAnimation(final WorkspaceItemInfo destInfo, final View destView,
-            final WorkspaceItemInfo srcInfo, final DragView srcView, Rect dstRect,
+            final WorkspaceItemInfo srcInfo, final DragObject d, Rect dstRect,
             float scaleRelativeToDragLayer) {
+        final DragView srcView = d.dragView;
         prepareCreateAnimation(destView);
         addItem(destInfo);
         // This will animate the first item from it's position as an icon into its
@@ -298,7 +299,7 @@
                 .start();
 
         // This will animate the dragView (srcView) into the new folder
-        onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1,
+        onDrop(srcInfo, d, dstRect, scaleRelativeToDragLayer, 1,
                 false /* itemReturnedOnFailedDrop */);
     }
 
@@ -313,11 +314,11 @@
         mOpenAlarm.cancelAlarm();
     }
 
-    private void onDrop(final WorkspaceItemInfo item, DragView animateView, Rect finalRect,
+    private void onDrop(final WorkspaceItemInfo item, DragObject d, Rect finalRect,
             float scaleRelativeToDragLayer, int index, boolean itemReturnedOnFailedDrop) {
         item.cellX = -1;
         item.cellY = -1;
-
+        DragView animateView = d.dragView;
         // Typically, the animateView corresponds to the DragView; however, if this is being done
         // after a configuration activity (ie. for a Shortcut being dragged from AllApps) we
         // will not have a view to animate
@@ -395,7 +396,7 @@
             String[] suggestedNameOut = new String[FolderNameProvider.SUGGEST_MAX];
             if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
                 Executors.UI_HELPER_EXECUTOR.post(() -> {
-                    launcher.getFolderNameProvider().getSuggestedFolderName(
+                    d.folderNameProvider.getSuggestedFolderName(
                             getContext(), mInfo.contents, suggestedNameOut);
                     showFinalView(finalIndex, item, suggestedNameOut);
                 });
@@ -429,9 +430,10 @@
             item = (WorkspaceItemInfo) d.dragInfo;
         }
         mFolder.notifyDrop();
-        onDrop(item, d.dragView, null, 1.0f,
+        onDrop(item, d, null, 1.0f,
                 itemReturnedOnFailedDrop ? item.rank : mInfo.contents.size(),
-                itemReturnedOnFailedDrop);
+                itemReturnedOnFailedDrop
+        );
     }
 
     public void setDotInfo(FolderDotInfo dotInfo) {
diff --git a/src/com/android/launcher3/folder/FolderNameEditText.java b/src/com/android/launcher3/folder/FolderNameEditText.java
index 7e3f847..7e11b18 100644
--- a/src/com/android/launcher3/folder/FolderNameEditText.java
+++ b/src/com/android/launcher3/folder/FolderNameEditText.java
@@ -61,6 +61,9 @@
         return connectionWrapper;
     }
 
+    /**
+     * Send strings in @param suggestList to the IME to show up as suggestions.
+     */
     public void displayCompletions(List<String> suggestList) {
         int cnt = Math.min(suggestList.size(), FolderNameProvider.SUGGEST_MAX);
         CompletionInfo[] cInfo = new CompletionInfo[cnt];
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index 9ea292c..957e636 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -24,6 +24,7 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.WorkspaceItemInfo;
+import com.android.launcher3.util.ResourceBasedOverride;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -38,10 +39,10 @@
 /**
  * Locates provider for the folder name.
  */
-public class FolderNameProvider {
+public class FolderNameProvider implements ResourceBasedOverride {
 
     private static final String TAG = "FolderNameProvider";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = true;
 
     /**
      * IME usually has up to 3 suggest slots. In total, there are 4 suggest slots as the folder
@@ -50,9 +51,14 @@
     public static final int SUGGEST_MAX = 4;
 
     /**
-     * When inheriting class requires precaching, override this method.
+     * Retrieve instance of this object that can be overridden in runtime based on the build
+     * variant of the application.
      */
-    public void load(Context context) {}
+    public static FolderNameProvider newInstance(Context context) {
+        FolderNameProvider fnp = Overrides.getObject(FolderNameProvider.class,
+                context.getApplicationContext(), R.string.folder_name_provider_class);
+        return fnp;
+    }
 
     public CharSequence getSuggestedFolderName(Context context,
             ArrayList<WorkspaceItemInfo> workspaceItemInfos, CharSequence[] candidates) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 571d41a..6faa22f 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -60,6 +60,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderGridOrganizer;
+import com.android.launcher3.folder.FolderNameProvider;
 import com.android.launcher3.icons.ComponentWithLabel;
 import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
 import com.android.launcher3.icons.IconCache;
@@ -256,6 +257,11 @@
                     mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated);
             logger.addSplit("save widgets in icon cache");
 
+            // fifth step
+            if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
+                loadFolderNames();
+            }
+
             verifyNotStopped();
             updateHandler.finish();
             logger.addSplit("finish icon update");
@@ -898,6 +904,21 @@
         return allShortcuts;
     }
 
+    private void loadFolderNames() {
+        FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext());
+
+        synchronized (mBgDataModel) {
+            for (int i = 0; i < mBgDataModel.folders.size(); i++) {
+                String[] suggestedOut = new String[FolderNameProvider.SUGGEST_MAX];
+                FolderInfo info = mBgDataModel.folders.valueAt(i);
+                if (info.suggestedFolderNames == null) {
+                    provider.getSuggestedFolderName(mApp.getContext(), info.contents, suggestedOut);
+                    info.suggestedFolderNames = new Intent().putExtra("suggest", suggestedOut);
+                }
+            }
+        }
+    }
+
     public static boolean isValidProvider(AppWidgetProviderInfo provider) {
         return (provider != null) && (provider.provider != null)
                 && (provider.provider.getPackageName() != null);