Removing unnecessary search header duplication

Bug: 268646258
Test: Verified on device
Change-Id: I33a7df6a523e5600dc6251c3d8feff1236362705
diff --git a/res/values/id.xml b/res/values/id.xml
index 52a7e98..375750f 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -19,7 +19,6 @@
     <item type="id" name="view_type_widgets_space" />
     <item type="id" name="view_type_widgets_list" />
     <item type="id" name="view_type_widgets_header" />
-    <item type="id" name="view_type_widgets_search_header" />
     <!--  Used for A11y actions in staged split to identify each task uniquely  -->
     <item type="id" name="split_topLeft_appInfo" />
     <item type="id" name="split_bottomRight_appInfo" />
diff --git a/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java b/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
index 1d1c9dc..f09f4c6 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
@@ -59,27 +59,12 @@
     @Rank
     public abstract int getRank();
 
-    /**
-     * Marker interface for subclasses that are headers for widget list items.
-     *
-     * @param <T> The type of this class.
-     */
-    public interface Header<T extends WidgetsListBaseEntry & Header<T>> {
-        /** Returns whether the widget list is currently expanded. */
-        boolean isWidgetListShown();
-
-        /** Returns a copy of the item with the widget list shown. */
-        T withWidgetListShown();
-    }
-
     @Retention(SOURCE)
-    @IntDef({RANK_WIDGETS_TOP_SPACE, RANK_WIDGETS_LIST_HEADER, RANK_WIDGETS_LIST_SEARCH_HEADER,
-            RANK_WIDGETS_LIST_CONTENT})
+    @IntDef({RANK_WIDGETS_TOP_SPACE, RANK_WIDGETS_LIST_HEADER, RANK_WIDGETS_LIST_CONTENT})
     public @interface Rank {
     }
 
     public static final int RANK_WIDGETS_TOP_SPACE = 1;
     public static final int RANK_WIDGETS_LIST_HEADER = 2;
-    public static final int RANK_WIDGETS_LIST_SEARCH_HEADER = 3;
-    public static final int RANK_WIDGETS_LIST_CONTENT = 4;
+    public static final int RANK_WIDGETS_LIST_CONTENT = 3;
 }
diff --git a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
index 5b3ea94..bb0cf92 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
@@ -15,35 +15,67 @@
  */
 package com.android.launcher3.widget.model;
 
+import android.content.Context;
+import android.content.res.Resources;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.util.PluralMessageFormat;
 
 import java.util.List;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
 
 /** An information holder for an app which has widgets or/and shortcuts. */
-public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry
-        implements WidgetsListBaseEntry.Header<WidgetsListHeaderEntry> {
+public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
 
-    public final int widgetsCount;
-    public final int shortcutsCount;
+    private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_SEARCH =
+            (context, entry) -> entry.mWidgets.stream()
+                    .map(item -> item.label).sorted().collect(Collectors.joining(", "));
+
+    private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_DEFAULT =
+            (context, entry) -> {
+                List<WidgetItem> items = entry.mWidgets;
+                int wc = (int) items.stream().filter(item -> item.widgetInfo != null).count();
+                int sc = Math.max(0, items.size() - wc);
+
+                Resources resources = context.getResources();
+                if (wc == 0 && sc == 0) {
+                    return null;
+                }
+
+                String subtitle;
+                if (wc > 0 && sc > 0) {
+                    String widgetsCount = PluralMessageFormat.getIcuPluralString(context,
+                            R.string.widgets_count, wc);
+                    String shortcutsCount = PluralMessageFormat.getIcuPluralString(context,
+                            R.string.shortcuts_count, sc);
+                    subtitle = resources.getString(R.string.widgets_and_shortcuts_count,
+                            widgetsCount, shortcutsCount);
+                } else if (wc > 0) {
+                    subtitle = PluralMessageFormat.getIcuPluralString(context,
+                            R.string.widgets_count, wc);
+                } else {
+                    subtitle = PluralMessageFormat.getIcuPluralString(context,
+                            R.string.shortcuts_count, sc);
+                }
+                return subtitle;
+            };
 
     private final boolean mIsWidgetListShown;
-
-    public WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
-            List<WidgetItem> items) {
-        this(pkgItem, titleSectionName, items, /* isWidgetListShown= */ false);
-    }
+    private final boolean mIsSearchEntry;
 
     private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
-            List<WidgetItem> items, boolean isWidgetListShown) {
+            List<WidgetItem> items, boolean isSearchEntry, boolean isWidgetListShown) {
         super(pkgItem, titleSectionName, items);
-        widgetsCount = (int) items.stream().filter(item -> item.widgetInfo != null).count();
-        shortcutsCount = Math.max(0, items.size() - widgetsCount);
+        mIsSearchEntry = isSearchEntry;
         mIsWidgetListShown = isWidgetListShown;
     }
 
     /** Returns {@code true} if the widgets list associated with this header is shown. */
-    @Override
     public boolean isWidgetListShown() {
         return mIsWidgetListShown;
     }
@@ -59,23 +91,54 @@
         return RANK_WIDGETS_LIST_HEADER;
     }
 
+    public boolean isSearchEntry() {
+        return mIsSearchEntry;
+    }
+
+    @Nullable
+    public String getSubtitle(Context context) {
+        return mIsSearchEntry
+                ? SUBTITLE_SEARCH.apply(context, this) : SUBTITLE_DEFAULT.apply(context, this);
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof WidgetsListHeaderEntry)) return false;
         WidgetsListHeaderEntry otherEntry = (WidgetsListHeaderEntry) obj;
         return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
                 && mTitleSectionName.equals(otherEntry.mTitleSectionName)
-                && mIsWidgetListShown == otherEntry.mIsWidgetListShown;
+                && mIsWidgetListShown == otherEntry.mIsWidgetListShown
+                && mIsSearchEntry == otherEntry.mIsSearchEntry;
     }
 
     /** Returns a copy of this {@link WidgetsListHeaderEntry} with the widget list shown. */
-    @Override
     public WidgetsListHeaderEntry withWidgetListShown() {
         if (mIsWidgetListShown) return this;
         return new WidgetsListHeaderEntry(
                 mPkgItem,
                 mTitleSectionName,
                 mWidgets,
+                mIsSearchEntry,
                 /* isWidgetListShown= */ true);
     }
+
+    public static WidgetsListHeaderEntry create(PackageItemInfo pkgItem, String titleSectionName,
+            List<WidgetItem> items) {
+        return new WidgetsListHeaderEntry(
+                pkgItem,
+                titleSectionName,
+                items,
+                /* forSearch */ false,
+                /* isWidgetListShown= */ false);
+    }
+
+    public static WidgetsListHeaderEntry createForSearch(PackageItemInfo pkgItem,
+            String titleSectionName, List<WidgetItem> items) {
+        return new WidgetsListHeaderEntry(
+                pkgItem,
+                titleSectionName,
+                items,
+                /* forSearch */ true,
+                /* isWidgetListShown= */ false);
+    }
 }
diff --git a/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java b/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java
deleted file mode 100644
index 055e4ec..0000000
--- a/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2021 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.widget.model;
-
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-
-import java.util.List;
-
-/** An information holder for an app which has widgets or/and shortcuts, to be shown in search. */
-public final class WidgetsListSearchHeaderEntry extends WidgetsListBaseEntry
-        implements WidgetsListBaseEntry.Header<WidgetsListSearchHeaderEntry> {
-
-    private final boolean mIsWidgetListShown;
-
-    public WidgetsListSearchHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
-            List<WidgetItem> items) {
-        this(pkgItem, titleSectionName, items, /* isWidgetListShown= */ false);
-    }
-
-    private WidgetsListSearchHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
-            List<WidgetItem> items, boolean isWidgetListShown) {
-        super(pkgItem, titleSectionName, items);
-        mIsWidgetListShown = isWidgetListShown;
-    }
-
-    /** Returns {@code true} if the widgets list associated with this header is shown. */
-    @Override
-    public boolean isWidgetListShown() {
-        return mIsWidgetListShown;
-    }
-
-    @Override
-    public String toString() {
-        return "SearchHeader:" + mPkgItem.packageName + ":" + mWidgets.size();
-    }
-
-    @Override
-    @Rank
-    public int getRank() {
-        return RANK_WIDGETS_LIST_SEARCH_HEADER;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof WidgetsListSearchHeaderEntry)) return false;
-        WidgetsListSearchHeaderEntry otherEntry = (WidgetsListSearchHeaderEntry) obj;
-        return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
-                && mTitleSectionName.equals(otherEntry.mTitleSectionName)
-                && mIsWidgetListShown == otherEntry.mIsWidgetListShown;
-    }
-
-    /** Returns a copy of this {@link WidgetsListSearchHeaderEntry} with the widget list shown. */
-    @Override
-    public WidgetsListSearchHeaderEntry withWidgetListShown() {
-        if (mIsWidgetListShown) return this;
-        return new WidgetsListSearchHeaderEntry(
-                mPkgItem,
-                mTitleSectionName,
-                mWidgets,
-                /* isWidgetListShown= */ true);
-    }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java b/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java
index 99374f5..d09fe84 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java
@@ -25,7 +25,6 @@
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
 import com.android.launcher3.widget.picker.WidgetsListAdapter.WidgetListBaseRowEntryComparator;
 
 import java.util.ArrayList;
@@ -175,12 +174,8 @@
      */
     private boolean hasHeaderUpdated(WidgetsListBaseEntry curRow, WidgetsListBaseEntry newRow) {
         if (newRow instanceof WidgetsListHeaderEntry && curRow instanceof WidgetsListHeaderEntry) {
-            return !curRow.equals(newRow);
-        }
-        if (newRow instanceof WidgetsListSearchHeaderEntry
-                && curRow instanceof WidgetsListSearchHeaderEntry) {
             // Always refresh search header entries to reset rounded corners in their view holder.
-            return true;
+            return !curRow.equals(newRow) || ((WidgetsListHeaderEntry) curRow).isSearchEntry();
         }
         return false;
     }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index bb80e9b..7c7cdf4 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -286,7 +286,7 @@
                 }
             };
             packageItemInfo.title = getContext().getString(R.string.suggested_widgets_header_title);
-            WidgetsListHeaderEntry widgetsListHeaderEntry = new WidgetsListHeaderEntry(
+            WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
                     packageItemInfo,
                     getContext().getString(R.string.suggested_widgets_header_title),
                     mActivityContext.getPopupDataProvider().getRecommendedWidgets())
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index dc1d2dc..549ac42 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -48,7 +48,6 @@
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -81,7 +80,6 @@
     public static final int VIEW_TYPE_WIDGETS_SPACE = R.id.view_type_widgets_space;
     public static final int VIEW_TYPE_WIDGETS_LIST = R.id.view_type_widgets_list;
     public static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
-    public static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
 
     private final Context mContext;
     private final WidgetsDiffReporter mDiffReporter;
@@ -96,7 +94,6 @@
 
     private Predicate<WidgetsListBaseEntry> mHeaderAndSelectedContentFilter = entry ->
             entry instanceof WidgetsListHeaderEntry
-                    || entry instanceof WidgetsListSearchHeaderEntry
                     || PackageUserKey.fromPackageItemInfo(entry.mPkgItem)
                             .equals(mWidgetsContentVisiblePackageUserKey);
     @Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
@@ -125,12 +122,6 @@
                         /* onHeaderClickListener= */ this,
                         listDrawableFactory));
         mViewHolderBinders.put(
-                VIEW_TYPE_WIDGETS_SEARCH_HEADER,
-                new WidgetsListSearchHeaderViewHolderBinder(
-                        layoutInflater,
-                        /* onHeaderClickListener= */ this,
-                        listDrawableFactory));
-        mViewHolderBinders.put(
                 VIEW_TYPE_WIDGETS_SPACE,
                 new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
     }
@@ -205,10 +196,10 @@
                         && (mHeaderChangeListener == null
                         || !(entry instanceof WidgetsListContentEntry)))
                 .map(entry -> {
-                    if (entry instanceof WidgetsListBaseEntry.Header<?>
+                    if (entry instanceof WidgetsListHeaderEntry
                             && matchesKey(entry, mWidgetsContentVisiblePackageUserKey)) {
                         // Adjust the original entries to expand headers for the selected content.
-                        return ((WidgetsListBaseEntry.Header<?>) entry).withWidgetListShown();
+                        return ((WidgetsListHeaderEntry) entry).withWidgetListShown();
                     } else if (entry instanceof WidgetsListContentEntry) {
                         // Adjust the original content entries to accommodate for the current
                         // maxSpanSize.
@@ -233,7 +224,7 @@
     /** Returns whether {@code entry} matches {@code key}. */
     private static boolean isHeaderForPackageUserKey(
             @NonNull WidgetsListBaseEntry entry, @Nullable PackageUserKey key) {
-        return entry instanceof WidgetsListBaseEntry.Header && matchesKey(entry, key);
+        return entry instanceof WidgetsListHeaderEntry && matchesKey(entry, key);
     }
 
     private static boolean matchesKey(@NonNull WidgetsListBaseEntry entry,
@@ -276,16 +267,11 @@
      * first header in the new list that gets generated as we search.
      */
     void selectFirstHeaderEntry() {
-        WidgetsListSearchHeaderEntry firstEntry = null;
-        for (WidgetsListBaseEntry entry: mVisibleEntries) {
-            if (entry instanceof WidgetsListSearchHeaderEntry) {
-                firstEntry = (WidgetsListSearchHeaderEntry) entry;
-                break;
-            }
-        }
-        if (firstEntry != null) {
-            onHeaderClicked(true, PackageUserKey.fromPackageItemInfo(firstEntry.mPkgItem));
-        }
+        mVisibleEntries.stream()
+                .filter(entry -> entry instanceof WidgetsListHeaderEntry)
+                .findFirst()
+                .ifPresent(entry ->
+                        onHeaderClicked(true, PackageUserKey.fromPackageItemInfo(entry.mPkgItem)));
     }
 
     @Override
@@ -325,8 +311,6 @@
             return VIEW_TYPE_WIDGETS_LIST;
         } else if (entry instanceof WidgetsListHeaderEntry) {
             return VIEW_TYPE_WIDGETS_HEADER;
-        } else if (entry instanceof WidgetsListSearchHeaderEntry) {
-            return VIEW_TYPE_WIDGETS_SEARCH_HEADER;
         } else if (entry instanceof WidgetListSpaceEntry) {
             return VIEW_TYPE_WIDGETS_SPACE;
         }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index 8c91d43..a6ef89f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -18,12 +18,12 @@
 import static com.android.launcher3.config.FeatureFlags.LARGE_SCREEN_WIDGET_PICKER;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.View;
@@ -45,13 +45,9 @@
 import com.android.launcher3.icons.cache.HandlerRunnable;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.PluralMessageFormat;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import java.util.stream.Collectors;
 
 /**
  * A UI represents a header of an app shown in the full widgets tray.
@@ -201,11 +197,6 @@
     /** Apply app icon, labels and tag using a generic {@link WidgetsListHeaderEntry}. */
     @UiThread
     public void applyFromItemInfoWithIcon(WidgetsListHeaderEntry entry) {
-        applyIconAndLabel(entry);
-    }
-
-    @UiThread
-    private void applyIconAndLabel(WidgetsListHeaderEntry entry) {
         PackageItemInfo info = entry.mPkgItem;
         setIcon(info.newIcon(getContext()));
         setTitles(entry);
@@ -247,55 +238,13 @@
     private void setTitles(WidgetsListHeaderEntry entry) {
         mTitle.setText(entry.mPkgItem.title);
 
-        Resources resources = getContext().getResources();
-        if (entry.widgetsCount == 0 && entry.shortcutsCount == 0) {
+        String subtitle = entry.getSubtitle(getContext());
+        if (TextUtils.isEmpty(subtitle)) {
             mSubtitle.setVisibility(GONE);
-            return;
-        }
-
-        String subtitle;
-        if (entry.widgetsCount > 0 && entry.shortcutsCount > 0) {
-            String widgetsCount = PluralMessageFormat.getIcuPluralString(getContext(),
-                    R.string.widgets_count, entry.widgetsCount);
-            String shortcutsCount = PluralMessageFormat.getIcuPluralString(getContext(),
-                    R.string.shortcuts_count, entry.shortcutsCount);
-            subtitle = resources.getString(R.string.widgets_and_shortcuts_count, widgetsCount,
-                    shortcutsCount);
-        } else if (entry.widgetsCount > 0) {
-            subtitle = PluralMessageFormat.getIcuPluralString(getContext(),
-                    R.string.widgets_count, entry.widgetsCount);
         } else {
-            subtitle = PluralMessageFormat.getIcuPluralString(getContext(),
-                    R.string.shortcuts_count, entry.shortcutsCount);
+            mSubtitle.setText(subtitle);
+            mSubtitle.setVisibility(VISIBLE);
         }
-        mSubtitle.setText(subtitle);
-        mSubtitle.setVisibility(VISIBLE);
-    }
-
-    /** Apply app icon, labels and tag using a generic {@link WidgetsListSearchHeaderEntry}. */
-    @UiThread
-    public void applyFromItemInfoWithIcon(WidgetsListSearchHeaderEntry entry) {
-        applyIconAndLabel(entry);
-    }
-
-    @UiThread
-    private void applyIconAndLabel(WidgetsListSearchHeaderEntry entry) {
-        PackageItemInfo info = entry.mPkgItem;
-        setIcon(info.newIcon(getContext()));
-        setTitles(entry);
-        setExpanded(entry.isWidgetListShown());
-
-        super.setTag(info);
-
-        verifyHighRes();
-    }
-
-    private void setTitles(WidgetsListSearchHeaderEntry entry) {
-        mTitle.setText(entry.mPkgItem.title);
-
-        mSubtitle.setText(entry.mWidgets.stream()
-                .map(item -> item.label).sorted().collect(Collectors.joining(", ")));
-        mSubtitle.setVisibility(VISIBLE);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
deleted file mode 100644
index 9e659fe..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2021 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.widget.picker;
-
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import com.android.launcher3.R;
-import com.android.launcher3.recyclerview.ViewHolderBinder;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import java.util.List;
-
-/**
- * Binds data from {@link WidgetsListHeaderEntry} to UI elements in {@link WidgetsListHeaderHolder}.
- */
-public final class WidgetsListSearchHeaderViewHolderBinder implements
-        ViewHolderBinder<WidgetsListSearchHeaderEntry, WidgetsListSearchHeaderHolder> {
-    private final LayoutInflater mLayoutInflater;
-    private final OnHeaderClickListener mOnHeaderClickListener;
-    private final WidgetsListDrawableFactory mListDrawableFactory;
-
-    public WidgetsListSearchHeaderViewHolderBinder(LayoutInflater layoutInflater,
-            OnHeaderClickListener onHeaderClickListener,
-            WidgetsListDrawableFactory listDrawableFactory) {
-        mLayoutInflater = layoutInflater;
-        mOnHeaderClickListener = onHeaderClickListener;
-        mListDrawableFactory = listDrawableFactory;
-    }
-
-    @Override
-    public WidgetsListSearchHeaderHolder newViewHolder(ViewGroup parent) {
-        WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
-                R.layout.widgets_list_row_header, parent, false);
-        header.setBackground(mListDrawableFactory.createHeaderBackgroundDrawable());
-        return new WidgetsListSearchHeaderHolder(header);
-    }
-
-    @Override
-    public void bindViewHolder(WidgetsListSearchHeaderHolder viewHolder,
-            WidgetsListSearchHeaderEntry data, @ListPosition int position, List<Object> payloads) {
-        WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
-        widgetsListHeader.applyFromItemInfoWithIcon(data);
-        widgetsListHeader.setSelected(data.isWidgetListShown());
-        widgetsListHeader.setExpanded(data.isWidgetListShown());
-        widgetsListHeader.setListDrawableState(
-                WidgetsListDrawableState.obtain(
-                        (position & POSITION_FIRST) != 0,
-                        (position & POSITION_LAST) != 0,
-                        /* isExpanded= */ data.isWidgetListShown()));
-        widgetsListHeader.setOnExpandChangeListener(isExpanded ->
-                mOnHeaderClickListener.onHeaderClicked(isExpanded,
-                        PackageUserKey.fromPackageItemInfo(data.mPkgItem)));
-    }
-}
diff --git a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
index 9be3b5f..613066a 100644
--- a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
+++ b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
@@ -28,7 +28,6 @@
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -72,7 +71,7 @@
                     List<WidgetItem> matchedWidgetItems = filterWidgetItems(
                             input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
                     if (matchedWidgetItems.size() > 0) {
-                        results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
+                        results.add(WidgetsListHeaderEntry.createForSearch(headerEntry.mPkgItem,
                                 headerEntry.mTitleSectionName, matchedWidgetItems));
                         results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
                                 headerEntry.mTitleSectionName, matchedWidgetItems));
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 702f343..f490333 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -87,7 +87,7 @@
             List<WidgetItem> widgetItems = entry.getValue();
             String sectionName = (pkgItem.title == null) ? "" :
                     indexer.computeSectionName(pkgItem.title);
-            result.add(new WidgetsListHeaderEntry(pkgItem, sectionName, widgetItems));
+            result.add(WidgetsListHeaderEntry.create(pkgItem, sectionName, widgetItems));
             result.add(new WidgetsListContentEntry(pkgItem, sectionName, widgetItems));
         }
         return result;
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
index b480a4c..8c87957 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
@@ -229,7 +229,7 @@
                 List.of(mHeaderA, mHeaderB, mContentE));
         // GIVEN the new list has one of the headers widgets list modified.
         List<WidgetsListBaseEntry> newList = List.of(
-                new WidgetsListHeaderEntry(
+                WidgetsListHeaderEntry.create(
                         mHeaderA.mPkgItem, mHeaderA.mTitleSectionName,
                         mHeaderA.mWidgets.subList(0, 1)),
                 mHeaderB, mContentE);
@@ -274,7 +274,7 @@
         PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
                 widgetItems.get(0).user);
 
-        return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+        return WidgetsListHeaderEntry.create(pInfo, /* titleSectionName= */ "", widgetItems);
     }
 
     private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
index 230b27f..0044d04 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
@@ -270,7 +270,8 @@
             pInfo.title = pInfo.packageName;
             pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
 
-            result.add(new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems));
+            result.add(WidgetsListHeaderEntry.create(
+                    pInfo, /* titleSectionName= */ "", widgetItems));
             result.add(new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems));
         }
 
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index 211318c..f53d15b 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -134,7 +134,7 @@
         appInfo.title = appName;
         appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
 
-        return new WidgetsListHeaderEntry(appInfo,
+        return WidgetsListHeaderEntry.create(appInfo,
                 /* titleSectionName= */ "",
                 generateWidgetItems(packageName, numOfWidgets));
     }
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
deleted file mode 100644
index 66c2f36..0000000
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2021 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.widget.picker;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.verify;
-
-import static java.util.Collections.EMPTY_LIST;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.UserHandle;
-import android.view.LayoutInflater;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.ComponentWithLabel;
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.ActivityContextWrapper;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.WidgetUtils;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class WidgetsListSearchHeaderViewHolderBinderTest {
-    private static final String TEST_PACKAGE = "com.google.test";
-    private static final String APP_NAME = "Test app";
-
-    private Context mContext;
-    private WidgetsListSearchHeaderViewHolderBinder mViewHolderBinder;
-    private InvariantDeviceProfile mTestProfile;
-
-    @Mock
-    private IconCache mIconCache;
-    @Mock
-    private OnHeaderClickListener mOnHeaderClickListener;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = new ActivityContextWrapper(getApplicationContext());
-        mTestProfile = new InvariantDeviceProfile();
-        mTestProfile.numRows = 5;
-        mTestProfile.numColumns = 5;
-
-        doAnswer(invocation -> {
-            ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
-            return componentWithLabel.getComponent().getShortClassName();
-        }).when(mIconCache).getTitleNoCache(any());
-        mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
-                LayoutInflater.from(mContext),
-                mOnHeaderClickListener,
-                new WidgetsListDrawableFactory(mContext));
-    }
-
-    @Test
-    public void bindViewHolder_appWith3Widgets_shouldShowTheCorrectAppNameAndSubtitle() {
-        WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
-                new FrameLayout(mContext));
-        WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
-        WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
-                APP_NAME,
-                TEST_PACKAGE,
-                /* numOfWidgets= */ 3);
-        mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
-
-        TextView appTitle = widgetsListHeader.findViewById(R.id.app_title);
-        TextView appSubtitle = widgetsListHeader.findViewById(R.id.app_subtitle);
-        assertThat(appTitle.getText()).isEqualTo(APP_NAME);
-        assertThat(appSubtitle.getText())
-                .isEqualTo(".SampleWidget0, .SampleWidget1, .SampleWidget2");
-    }
-
-    @Test
-    public void bindViewHolder_shouldAttachOnHeaderClickListener() {
-        WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
-                new FrameLayout(mContext));
-        WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
-        WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
-                APP_NAME,
-                TEST_PACKAGE,
-                /* numOfWidgets= */ 3);
-
-        mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
-        widgetsListHeader.callOnClick();
-
-        verify(mOnHeaderClickListener).onHeaderClicked(eq(true),
-                eq(PackageUserKey.fromPackageItemInfo(entry.mPkgItem)));
-    }
-
-    private WidgetsListSearchHeaderEntry generateSampleSearchHeader(String appName,
-            String packageName, int numOfWidgets) {
-        PackageItemInfo appInfo = new PackageItemInfo(packageName, UserHandle.CURRENT);
-        appInfo.title = appName;
-        appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
-
-        return new WidgetsListSearchHeaderEntry(appInfo,
-                /* titleSectionName= */ "",
-                generateWidgetItems(packageName, numOfWidgets));
-    }
-
-    private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
-        ArrayList<WidgetItem> widgetItems = new ArrayList<>();
-        for (int i = 0; i < numOfWidgets; i++) {
-            ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
-            AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
-
-            widgetItems.add(new WidgetItem(
-                    LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
-                    mTestProfile, mIconCache));
-        }
-        return widgetItems;
-    }
-}
diff --git a/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java b/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
index d812ab0..0124f73 100644
--- a/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
@@ -50,7 +50,6 @@
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -117,12 +116,12 @@
                 .getAllWidgets();
 
         assertEquals(List.of(
-                new WidgetsListSearchHeaderEntry(
+                WidgetsListHeaderEntry.createForSearch(
                         mCalendarHeaderEntry.mPkgItem,
                         mCalendarHeaderEntry.mTitleSectionName,
                         mCalendarHeaderEntry.mWidgets),
                 mCalendarContentEntry,
-                new WidgetsListSearchHeaderEntry(
+                WidgetsListHeaderEntry.createForSearch(
                         mCameraHeaderEntry.mPkgItem,
                         mCameraHeaderEntry.mTitleSectionName,
                         mCameraHeaderEntry.mWidgets),
@@ -138,7 +137,7 @@
                 .getAllWidgets();
 
         assertEquals(List.of(
-                new WidgetsListSearchHeaderEntry(
+                WidgetsListHeaderEntry.createForSearch(
                         mCalendarHeaderEntry.mPkgItem,
                         mCalendarHeaderEntry.mTitleSectionName,
                         mCalendarHeaderEntry.mWidgets.subList(1, 2)),
@@ -146,7 +145,7 @@
                         mCalendarHeaderEntry.mPkgItem,
                         mCalendarHeaderEntry.mTitleSectionName,
                         mCalendarHeaderEntry.mWidgets.subList(1, 2)),
-                new WidgetsListSearchHeaderEntry(
+                WidgetsListHeaderEntry.createForSearch(
                         mCameraHeaderEntry.mPkgItem,
                         mCameraHeaderEntry.mTitleSectionName,
                         mCameraHeaderEntry.mWidgets.subList(1, 3)),
@@ -175,7 +174,7 @@
         PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
                 widgetItems.get(0).user);
 
-        return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+        return WidgetsListHeaderEntry.create(pInfo, /* titleSectionName= */ "", widgetItems);
     }
 
     private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,