Polish search result icons

SearchResultIconRow consumes a loaded ItemInfoWithIcon from its child SearchResult and updates other siblings with itemInfo.

preview: https://drive.google.com/file/d/1ijZsR5Q6M0DeZdlRJWpRb4AKmmTLBElY/view?usp=sharing
Change-Id: Ibb3fb697494749fd2e886dcdaa93241767a65944
diff --git a/src/com/android/launcher3/views/SearchResultIcon.java b/src/com/android/launcher3/views/SearchResultIcon.java
index 0851b54..51c741b 100644
--- a/src/com/android/launcher3/views/SearchResultIcon.java
+++ b/src/com/android/launcher3/views/SearchResultIcon.java
@@ -30,8 +30,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.UiThread;
-
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
@@ -49,6 +47,8 @@
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
 
+import java.util.function.Consumer;
+
 /**
  * A {@link BubbleTextView} representing a single cell result in AllApps
  */
@@ -61,7 +61,6 @@
     public static final String TARGET_TYPE_HERO_APP = "hero_app";
     public static final String TARGET_TYPE_SHORTCUT = "shortcut";
     public static final String TARGET_TYPE_REMOTE_ACTION = "remote_action";
-    public static final String TARGET_TYPE_SUGGEST = "suggest";
 
     public static final String REMOTE_ACTION_SHOULD_START = "should_start_for_result";
     public static final String REMOTE_ACTION_TOKEN = "action_token";
@@ -73,6 +72,7 @@
     private final Launcher mLauncher;
 
     private SearchTarget mSearchTarget;
+    private Consumer<ItemInfoWithIcon> mOnItemInfoChanged;
 
     public SearchResultIcon(Context context) {
         this(context, null, 0);
@@ -98,6 +98,15 @@
                 mLauncher.getDeviceProfile().allAppsCellHeightPx));
     }
 
+    /**
+     * Applies search target with a ItemInfoWithIcon consumer to be called after itemInfo is
+     * constructed
+     */
+    public void applySearchTarget(SearchTarget searchTarget, Consumer<ItemInfoWithIcon> cb) {
+        mOnItemInfoChanged = cb;
+        applySearchTarget(searchTarget);
+    }
+
     @Override
     public void applySearchTarget(SearchTarget searchTarget) {
         mSearchTarget = searchTarget;
@@ -111,7 +120,6 @@
                 prepareUsingShortcutInfo(searchTarget.getShortcutInfos().get(0));
                 break;
             case TARGET_TYPE_REMOTE_ACTION:
-            case TARGET_TYPE_SUGGEST:
                 prepareUsingRemoteAction(searchTarget.getRemoteAction(),
                         searchTarget.getExtras().getString(REMOTE_ACTION_TOKEN),
                         searchTarget.getExtras().getBoolean(REMOTE_ACTION_SHOULD_START),
@@ -124,53 +132,45 @@
         AllAppsStore appsStore = mLauncher.getAppsView().getAppsStore();
         AppInfo appInfo = appsStore.getApp(new ComponentKey(componentName, userHandle));
         applyFromApplicationInfo(appInfo);
+        notifyItemInfoChanged(appInfo);
     }
 
 
     private void prepareUsingShortcutInfo(ShortcutInfo shortcutInfo) {
         WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(shortcutInfo, getContext());
-        applyFromWorkspaceItem(workspaceItemInfo);
+        notifyItemInfoChanged(workspaceItemInfo);
         LauncherAppState launcherAppState = LauncherAppState.getInstance(getContext());
         MODEL_EXECUTOR.execute(() -> {
             launcherAppState.getIconCache().getShortcutIcon(workspaceItemInfo, shortcutInfo);
-            reapplyItemInfoAsync(workspaceItemInfo);
+            MAIN_EXECUTOR.post(() -> applyFromWorkspaceItem(workspaceItemInfo));
         });
     }
 
     private void prepareUsingRemoteAction(RemoteAction remoteAction, String token, boolean start,
             boolean useIconToBadge) {
         RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(remoteAction, token, start);
+        notifyItemInfoChanged(itemInfo);
+        UI_HELPER_EXECUTOR.post(() -> {
+            // If the Drawable from the remote action is not AdaptiveBitmap, styling will not
+            // work.
+            try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
+                Drawable d = itemInfo.getRemoteAction().getIcon().loadDrawable(getContext());
+                BitmapInfo bitmap = li.createBadgedIconBitmap(d, itemInfo.user,
+                        Build.VERSION.SDK_INT);
 
-        applyFromRemoteActionInfo(itemInfo);
-        if (!loadIconFromResource()) {
-            UI_HELPER_EXECUTOR.post(() -> {
-                // If the Drawable from the remote action is not AdaptiveBitmap, styling will not
-                // work.
-                try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
-                    Drawable d = itemInfo.getRemoteAction().getIcon().loadDrawable(getContext());
-                    BitmapInfo bitmap = li.createBadgedIconBitmap(d, itemInfo.user,
-                            Build.VERSION.SDK_INT);
-
-                    if (useIconToBadge) {
-                        BitmapInfo placeholder = li.createIconBitmap(
-                                itemInfo.getRemoteAction().getTitle().toString().substring(0, 1),
-                                bitmap.color);
-                        itemInfo.bitmap = li.badgeBitmap(placeholder.icon, bitmap);
-                    } else {
-                        itemInfo.bitmap = bitmap;
-                    }
-                    reapplyItemInfoAsync(itemInfo);
+                if (useIconToBadge) {
+                    BitmapInfo placeholder = li.createIconBitmap(
+                            itemInfo.getRemoteAction().getTitle().toString().substring(0, 1),
+                            bitmap.color);
+                    itemInfo.bitmap = li.badgeBitmap(placeholder.icon, bitmap);
+                } else {
+                    itemInfo.bitmap = bitmap;
                 }
-            });
-        }
+            }
+            MAIN_EXECUTOR.post(() -> applyFromRemoteActionInfo(itemInfo));
+        });
     }
 
-    @UiThread
-    void reapplyItemInfoAsync(ItemInfoWithIcon itemInfoWithIcon) {
-        MAIN_EXECUTOR.post(() -> reapplyItemInfo(itemInfoWithIcon));
-    }
-
-
     @Override
     public void handleSelection(int eventType) {
         mLauncher.getItemOnClickListener().onClick(this);
@@ -208,7 +208,10 @@
         return false;
     }
 
-    protected boolean loadIconFromResource() {
-        return false;
+    private void notifyItemInfoChanged(ItemInfoWithIcon itemInfoWithIcon) {
+        if (mOnItemInfoChanged != null) {
+            mOnItemInfoChanged.accept(itemInfoWithIcon);
+            mOnItemInfoChanged = null;
+        }
     }
 }
diff --git a/src/com/android/launcher3/views/SearchResultIconRow.java b/src/com/android/launcher3/views/SearchResultIconRow.java
index ecf5054..e3c7661 100644
--- a/src/com/android/launcher3/views/SearchResultIconRow.java
+++ b/src/com/android/launcher3/views/SearchResultIconRow.java
@@ -46,6 +46,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * A full width representation of {@link SearchResultIcon} with a secondary label and inline
@@ -53,7 +54,7 @@
  */
 public class SearchResultIconRow extends LinearLayout implements
         AllAppsSearchBarController.SearchTargetHandler, View.OnClickListener,
-        View.OnLongClickListener {
+        View.OnLongClickListener, Consumer<ItemInfoWithIcon> {
     public static final int MAX_SHORTCUTS_COUNT = 2;
 
 
@@ -95,6 +96,7 @@
         mShortcutViews[1] = findViewById(R.id.shortcut_1);
         mResultIcon.getLayoutParams().height = iconSize;
         mResultIcon.getLayoutParams().width = iconSize;
+        mResultIcon.setTextVisibility(false);
         for (BubbleTextView bubbleTextView : mShortcutViews) {
             ViewGroup.LayoutParams lp = bubbleTextView.getLayoutParams();
             lp.width = iconSize;
@@ -113,9 +115,7 @@
     @Override
     public void applySearchTarget(SearchTarget searchTarget) {
         mSearchTarget = searchTarget;
-        mResultIcon.applySearchTarget(searchTarget);
-        mResultIcon.setTextVisibility(false);
-        mTitleView.setText(mResultIcon.getText());
+        mResultIcon.applySearchTarget(searchTarget, this);
         String itemType = searchTarget.getItemType();
         boolean showDesc = itemType.equals(SearchResultIcon.TARGET_TYPE_SHORTCUT);
         mDescriptionView.setVisibility(showDesc ? VISIBLE : GONE);
@@ -138,6 +138,11 @@
         }
     }
 
+    @Override
+    public void accept(ItemInfoWithIcon itemInfoWithIcon) {
+        mTitleView.setText(itemInfoWithIcon.title);
+    }
+
     private void showInlineShortcuts(List<ShortcutInfo> infos) {
         if (infos == null) return;
         ArrayList<Pair<ShortcutInfo, ItemInfoWithIcon>> shortcuts = new ArrayList<>();
diff --git a/src/com/android/launcher3/views/SearchResultSuggestion.java b/src/com/android/launcher3/views/SearchResultSuggestion.java
index ab94bf0..c67b1cf 100644
--- a/src/com/android/launcher3/views/SearchResultSuggestion.java
+++ b/src/com/android/launcher3/views/SearchResultSuggestion.java
@@ -28,6 +28,7 @@
  */
 public class SearchResultSuggestion extends SearchResultIcon {
 
+    public static final String TARGET_TYPE_SUGGEST = "suggest";
     private final Drawable mCustomIcon;
 
     public SearchResultSuggestion(Context context) {
@@ -55,8 +56,7 @@
     }
 
     @Override
-    protected boolean loadIconFromResource() {
-        setIcon(mCustomIcon);
-        return true;
+    protected void setIcon(Drawable icon) {
+        super.setIcon(mCustomIcon);
     }
 }