Simplifying widget search pipeline

Bug: 183607616
Test: Verified on device
Change-Id: I3e5dd9e280f375475d1e1cf41dff6e6533175ebf
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
index c2bf1ae..36b6f01 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
@@ -18,64 +18,197 @@
 
 import static android.os.Looper.getMainLooper;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.matches;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 import static org.robolectric.Shadows.shadowOf;
 
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.UserHandle;
+
+import com.android.launcher3.InvariantDeviceProfile;
+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.popup.PopupDataProvider;
 import com.android.launcher3.search.SearchCallback;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 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;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowPackageManager;
+import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-import java.util.function.Consumer;
 
 @RunWith(RobolectricTestRunner.class)
 public class SimpleWidgetsSearchAlgorithmTest {
 
+    @Mock private IconCache mIconCache;
+
+    private InvariantDeviceProfile mTestProfile;
+    private WidgetsListHeaderEntry mCalendarHeaderEntry;
+    private WidgetsListContentEntry mCalendarContentEntry;
+    private WidgetsListHeaderEntry mCameraHeaderEntry;
+    private WidgetsListContentEntry mCameraContentEntry;
+    private WidgetsListHeaderEntry mClockHeaderEntry;
+    private WidgetsListContentEntry mClockContentEntry;
+    private Context mContext;
+
     private SimpleWidgetsSearchAlgorithm mSimpleWidgetsSearchAlgorithm;
     @Mock
-    private WidgetsPickerSearchPipeline mSearchPipeline;
+    private PopupDataProvider mDataProvider;
     @Mock
     private SearchCallback<WidgetsListBaseEntry> mSearchCallback;
-    @Captor
-    private ArgumentCaptor<Consumer<List<WidgetsListBaseEntry>>> mConsumerCaptor;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mSimpleWidgetsSearchAlgorithm = new SimpleWidgetsSearchAlgorithm(mSearchPipeline);
+        doAnswer(invocation -> {
+            ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
+            return componentWithLabel.getComponent().getShortClassName();
+        }).when(mIconCache).getTitleNoCache(any());
+        mTestProfile = new InvariantDeviceProfile();
+        mTestProfile.numRows = 5;
+        mTestProfile.numColumns = 5;
+        mContext = RuntimeEnvironment.application;
+
+        mCalendarHeaderEntry =
+                createWidgetsHeaderEntry("com.example.android.Calendar", "Calendar", 2);
+        mCalendarContentEntry =
+                createWidgetsContentEntry("com.example.android.Calendar", "Calendar", 2);
+        mCameraHeaderEntry = createWidgetsHeaderEntry("com.example.android.Camera", "Camera", 11);
+        mCameraContentEntry = createWidgetsContentEntry("com.example.android.Camera", "Camera", 11);
+        mClockHeaderEntry = createWidgetsHeaderEntry("com.example.android.Clock", "Clock", 3);
+        mClockContentEntry = createWidgetsContentEntry("com.example.android.Clock", "Clock", 3);
+
+
+        mSimpleWidgetsSearchAlgorithm = new SimpleWidgetsSearchAlgorithm(mDataProvider);
+        doReturn(Collections.EMPTY_LIST).when(mDataProvider).getAllWidgets();
     }
 
     @Test
-    public void doSearch_shouldQueryPipeline() {
-        mSimpleWidgetsSearchAlgorithm.doSearch("abc", mSearchCallback);
+    public void filter_shouldMatchOnAppName() {
+        doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
+                mCameraContentEntry, mClockHeaderEntry, mClockContentEntry))
+                .when(mDataProvider)
+                .getAllWidgets();
 
-        verify(mSearchPipeline).query(eq("abc"), any());
+        assertEquals(List.of(
+                new WidgetsListSearchHeaderEntry(
+                        mCalendarHeaderEntry.mPkgItem,
+                        mCalendarHeaderEntry.mTitleSectionName,
+                        mCalendarHeaderEntry.mWidgets),
+                mCalendarContentEntry,
+                new WidgetsListSearchHeaderEntry(
+                        mCameraHeaderEntry.mPkgItem,
+                        mCameraHeaderEntry.mTitleSectionName,
+                        mCameraHeaderEntry.mWidgets),
+                mCameraContentEntry),
+                SimpleWidgetsSearchAlgorithm.getFilteredWidgets(mDataProvider, "Ca"));
     }
 
     @Test
-    public void doSearch_shouldInformSearchCallbackOnQueryResult() {
-        ArrayList<WidgetsListBaseEntry> baseEntries = new ArrayList<>();
+    public void filter_shouldMatchOnWidgetLabel() {
+        doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
+                mCameraContentEntry))
+                .when(mDataProvider)
+                .getAllWidgets();
 
-        mSimpleWidgetsSearchAlgorithm.doSearch("abc", mSearchCallback);
+        assertEquals(List.of(
+                new WidgetsListSearchHeaderEntry(
+                        mCalendarHeaderEntry.mPkgItem,
+                        mCalendarHeaderEntry.mTitleSectionName,
+                        mCalendarHeaderEntry.mWidgets.subList(1, 2)),
+                new WidgetsListContentEntry(
+                        mCalendarHeaderEntry.mPkgItem,
+                        mCalendarHeaderEntry.mTitleSectionName,
+                        mCalendarHeaderEntry.mWidgets.subList(1, 2)),
+                new WidgetsListSearchHeaderEntry(
+                        mCameraHeaderEntry.mPkgItem,
+                        mCameraHeaderEntry.mTitleSectionName,
+                        mCameraHeaderEntry.mWidgets.subList(1, 3)),
+                new WidgetsListContentEntry(
+                        mCameraHeaderEntry.mPkgItem,
+                        mCameraHeaderEntry.mTitleSectionName,
+                        mCameraHeaderEntry.mWidgets.subList(1, 3))),
+                SimpleWidgetsSearchAlgorithm.getFilteredWidgets(mDataProvider, "Widget1"));
+    }
 
-        verify(mSearchPipeline).query(eq("abc"), mConsumerCaptor.capture());
-        mConsumerCaptor.getValue().accept(baseEntries);
+    @Test
+    public void doSearch_shouldInformCallback() {
+        doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
+                mCameraContentEntry, mClockHeaderEntry, mClockContentEntry))
+                .when(mDataProvider)
+                .getAllWidgets();
+        mSimpleWidgetsSearchAlgorithm.doSearch("Ca", mSearchCallback);
         shadowOf(getMainLooper()).idle();
-        // Verify SearchCallback#onSearchResult receives a query token along with the search
-        // results. The query token is the original query string concatenated with the query
-        // timestamp.
-        verify(mSearchCallback).onSearchResult(matches("abc\t\\d*"), eq(baseEntries));
+        verify(mSearchCallback).onSearchResult(
+                matches("Ca"), argThat(a -> a != null && !a.isEmpty()));
+    }
+
+    private WidgetsListHeaderEntry createWidgetsHeaderEntry(String packageName, String appName,
+            int numOfWidgets) {
+        List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
+        PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
+                widgetItems.get(0).user);
+
+        return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+    }
+
+    private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
+            int numOfWidgets) {
+        List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
+        PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
+                widgetItems.get(0).user);
+
+        return new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+    }
+
+    private PackageItemInfo createPackageItemInfo(String packageName, String appName,
+            UserHandle userHandle) {
+        PackageItemInfo pInfo = new PackageItemInfo(packageName);
+        pInfo.title = appName;
+        pInfo.user = userHandle;
+        pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
+        return pInfo;
+    }
+
+    private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
+        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
+        ArrayList<WidgetItem> widgetItems = new ArrayList<>();
+        for (int i = 0; i < numOfWidgets; i++) {
+            ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
+            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
+            widgetInfo.provider = cn;
+            ReflectionHelpers.setField(widgetInfo, "providerInfo",
+                    packageManager.addReceiverIfNotPresent(cn));
+
+            WidgetItem widgetItem = new WidgetItem(
+                    LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
+                    mTestProfile, mIconCache);
+            widgetItems.add(widgetItem);
+        }
+        return widgetItems;
     }
 }
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipelineTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipelineTest.java
deleted file mode 100644
index 17ededd..0000000
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipelineTest.java
+++ /dev/null
@@ -1,185 +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.search;
-
-import static android.os.Looper.getMainLooper;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.robolectric.Shadows.shadowOf;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.UserHandle;
-
-import com.android.launcher3.InvariantDeviceProfile;
-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.widget.LauncherAppWidgetProviderInfo;
-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;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-public class SimpleWidgetsSearchPipelineTest {
-    @Mock private IconCache mIconCache;
-
-    private InvariantDeviceProfile mTestProfile;
-    private WidgetsListHeaderEntry mCalendarHeaderEntry;
-    private WidgetsListContentEntry mCalendarContentEntry;
-    private WidgetsListHeaderEntry mCameraHeaderEntry;
-    private WidgetsListContentEntry mCameraContentEntry;
-    private WidgetsListHeaderEntry mClockHeaderEntry;
-    private WidgetsListContentEntry mClockContentEntry;
-    private Context mContext;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        doAnswer(invocation -> {
-            ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
-            return componentWithLabel.getComponent().getShortClassName();
-        }).when(mIconCache).getTitleNoCache(any());
-        mTestProfile = new InvariantDeviceProfile();
-        mTestProfile.numRows = 5;
-        mTestProfile.numColumns = 5;
-        mContext = RuntimeEnvironment.application;
-
-        mCalendarHeaderEntry =
-                createWidgetsHeaderEntry("com.example.android.Calendar", "Calendar", 2);
-        mCalendarContentEntry =
-                createWidgetsContentEntry("com.example.android.Calendar", "Calendar", 2);
-        mCameraHeaderEntry = createWidgetsHeaderEntry("com.example.android.Camera", "Camera", 11);
-        mCameraContentEntry = createWidgetsContentEntry("com.example.android.Camera", "Camera", 11);
-        mClockHeaderEntry = createWidgetsHeaderEntry("com.example.android.Clock", "Clock", 3);
-        mClockContentEntry = createWidgetsContentEntry("com.example.android.Clock", "Clock", 3);
-    }
-
-    @Test
-    public void query_shouldMatchOnAppName() {
-        SimpleWidgetsSearchPipeline pipeline = new SimpleWidgetsSearchPipeline(
-                List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
-                        mCameraContentEntry, mClockHeaderEntry, mClockContentEntry));
-
-        pipeline.query("Ca", results ->
-                assertEquals(results,
-                        List.of(
-                                new WidgetsListSearchHeaderEntry(
-                                        mCalendarHeaderEntry.mPkgItem,
-                                        mCalendarHeaderEntry.mTitleSectionName,
-                                        mCalendarHeaderEntry.mWidgets),
-                                mCalendarContentEntry,
-                                new WidgetsListSearchHeaderEntry(
-                                        mCameraHeaderEntry.mPkgItem,
-                                        mCameraHeaderEntry.mTitleSectionName,
-                                        mCameraHeaderEntry.mWidgets),
-                                mCameraContentEntry)));
-        shadowOf(getMainLooper()).idle();
-    }
-
-    @Test
-    public void query_shouldMatchOnWidgetLabel() {
-        SimpleWidgetsSearchPipeline pipeline = new SimpleWidgetsSearchPipeline(
-                List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
-                        mCameraContentEntry));
-
-        pipeline.query("Widget1", results ->
-                assertEquals(results,
-                        List.of(
-                                new WidgetsListSearchHeaderEntry(
-                                        mCalendarHeaderEntry.mPkgItem,
-                                        mCalendarHeaderEntry.mTitleSectionName,
-                                        mCalendarHeaderEntry.mWidgets.subList(1, 2)),
-                                new WidgetsListContentEntry(
-                                        mCalendarHeaderEntry.mPkgItem,
-                                        mCalendarHeaderEntry.mTitleSectionName,
-                                        mCalendarHeaderEntry.mWidgets.subList(1, 2)),
-                                new WidgetsListSearchHeaderEntry(
-                                        mCameraHeaderEntry.mPkgItem,
-                                        mCameraHeaderEntry.mTitleSectionName,
-                                        mCameraHeaderEntry.mWidgets.subList(1, 3)),
-                                new WidgetsListContentEntry(
-                                        mCameraHeaderEntry.mPkgItem,
-                                        mCameraHeaderEntry.mTitleSectionName,
-                                        mCameraHeaderEntry.mWidgets.subList(1, 3)))));
-        shadowOf(getMainLooper()).idle();
-    }
-
-    private WidgetsListHeaderEntry createWidgetsHeaderEntry(String packageName, String appName,
-            int numOfWidgets) {
-        List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
-        PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
-                widgetItems.get(0).user);
-
-        return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
-    }
-
-    private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
-            int numOfWidgets) {
-        List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
-        PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
-                widgetItems.get(0).user);
-
-        return new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems);
-    }
-
-    private PackageItemInfo createPackageItemInfo(String packageName, String appName,
-            UserHandle userHandle) {
-        PackageItemInfo pInfo = new PackageItemInfo(packageName);
-        pInfo.title = appName;
-        pInfo.user = userHandle;
-        pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
-        return pInfo;
-    }
-
-    private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
-        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
-        ArrayList<WidgetItem> widgetItems = new ArrayList<>();
-        for (int i = 0; i < numOfWidgets; i++) {
-            ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
-            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
-            widgetInfo.provider = cn;
-            ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                    packageManager.addReceiverIfNotPresent(cn));
-
-            WidgetItem widgetItem = new WidgetItem(
-                    LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
-                    mTestProfile, mIconCache);
-            widgetItems.add(widgetItem);
-        }
-        return widgetItems;
-    }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index d13884a..a4257a2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -169,7 +169,7 @@
         onWidgetsBound();
 
         mSearchAndRecommendationViewHolder.mSearchBar.initialize(
-                mLauncher.getPopupDataProvider().getAllWidgets(), /* searchModeListener= */ this);
+                mLauncher.getPopupDataProvider(), /* searchModeListener= */ this);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
index 56a08b1..42f1bb2 100644
--- a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
+++ b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
@@ -26,10 +26,7 @@
 
 import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.R;
-import com.android.launcher3.search.SearchAlgorithm;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.List;
+import com.android.launcher3.popup.PopupDataProvider;
 
 /**
  * View for a search bar with an edit text with a cancel button.
@@ -54,12 +51,10 @@
     }
 
     @Override
-    public void initialize(List<WidgetsListBaseEntry> allWidgets,
-            SearchModeListener searchModeListener) {
-        SearchAlgorithm<WidgetsListBaseEntry> algo =
-                new SimpleWidgetsSearchAlgorithm(new SimpleWidgetsSearchPipeline(allWidgets));
+    public void initialize(PopupDataProvider dataProvider, SearchModeListener searchModeListener) {
         mController = new WidgetsSearchBarController(
-                algo, mEditText, mCancelButton, searchModeListener);
+                new SimpleWidgetsSearchAlgorithm(dataProvider),
+                mEditText, mCancelButton, searchModeListener);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
index 15d2454..9be3b5f 100644
--- a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
+++ b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
@@ -16,42 +16,41 @@
 
 package com.android.launcher3.widget.picker.search;
 
-import android.os.Handler;
-import android.util.Log;
+import static com.android.launcher3.search.StringMatcherUtility.matches;
 
+import android.os.Handler;
+
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.search.SearchAlgorithm;
 import com.android.launcher3.search.SearchCallback;
+import com.android.launcher3.search.StringMatcherUtility.StringMatcher;
 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;
+import java.util.stream.Collectors;
 
 /**
  * Implementation of {@link SearchAlgorithm} that posts a task to query on the main thread.
  */
 public final class SimpleWidgetsSearchAlgorithm implements SearchAlgorithm<WidgetsListBaseEntry> {
 
-    private static final boolean DEBUG = false;
-    private static final String TAG = "SimpleWidgetsSearchAlgo";
-    private static final String DELIM = "\t";
-
     private final Handler mResultHandler;
-    private final WidgetsPickerSearchPipeline mSearchPipeline;
+    private final PopupDataProvider mDataProvider;
 
-    public SimpleWidgetsSearchAlgorithm(WidgetsPickerSearchPipeline searchPipeline) {
+    public SimpleWidgetsSearchAlgorithm(PopupDataProvider dataProvider) {
         mResultHandler = new Handler();
-        mSearchPipeline = searchPipeline;
+        mDataProvider = dataProvider;
     }
 
     @Override
     public void doSearch(String query, SearchCallback<WidgetsListBaseEntry> callback) {
-        long startTime = System.currentTimeMillis();
-        String queryToken = query + DELIM + startTime;
-        if (DEBUG) {
-            Log.d(TAG, "doSearch queryToken:" + queryToken);
-        }
-        mSearchPipeline.query(query,
-                results -> mResultHandler.post(
-                        () -> callback.onSearchResult(queryToken, new ArrayList(results))));
+        ArrayList<WidgetsListBaseEntry> result = getFilteredWidgets(mDataProvider, query);
+        mResultHandler.post(() -> callback.onSearchResult(query, result));
     }
 
     @Override
@@ -60,4 +59,36 @@
             mResultHandler.removeCallbacksAndMessages(/*token= */null);
         }
     }
+
+    /**
+     * Returns entries for all matched widgets
+     */
+    public static ArrayList<WidgetsListBaseEntry> getFilteredWidgets(
+            PopupDataProvider dataProvider, String input) {
+        ArrayList<WidgetsListBaseEntry> results = new ArrayList<>();
+        dataProvider.getAllWidgets().stream()
+                .filter(entry -> entry instanceof WidgetsListHeaderEntry)
+                .forEach(headerEntry -> {
+                    List<WidgetItem> matchedWidgetItems = filterWidgetItems(
+                            input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
+                    if (matchedWidgetItems.size() > 0) {
+                        results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
+                                headerEntry.mTitleSectionName, matchedWidgetItems));
+                        results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
+                                headerEntry.mTitleSectionName, matchedWidgetItems));
+                    }
+                });
+        return results;
+    }
+
+    private static List<WidgetItem> filterWidgetItems(String query, String packageTitle,
+            List<WidgetItem> items) {
+        StringMatcher matcher = StringMatcher.getInstance();
+        if (matches(query, packageTitle, matcher)) {
+            return items;
+        }
+        return items.stream()
+                .filter(item -> matches(query, item.label, matcher))
+                .collect(Collectors.toList());
+    }
 }
diff --git a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipeline.java b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipeline.java
deleted file mode 100644
index 5222e8e..0000000
--- a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipeline.java
+++ /dev/null
@@ -1,72 +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.search;
-
-import static com.android.launcher3.search.StringMatcherUtility.matches;
-
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.search.StringMatcherUtility.StringMatcher;
-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;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
-/**
- * Implementation of {@link WidgetsPickerSearchPipeline} that performs search by prefix matching on
- * app names and widget labels.
- */
-public final class SimpleWidgetsSearchPipeline implements WidgetsPickerSearchPipeline {
-
-    private final List<WidgetsListBaseEntry> mAllEntries;
-
-    public SimpleWidgetsSearchPipeline(List<WidgetsListBaseEntry> allEntries) {
-        mAllEntries = allEntries;
-    }
-
-    @Override
-    public void query(String input, Consumer<List<WidgetsListBaseEntry>> callback) {
-        ArrayList<WidgetsListBaseEntry> results = new ArrayList<>();
-        mAllEntries.stream().filter(entry -> entry instanceof WidgetsListHeaderEntry)
-                .forEach(headerEntry -> {
-                    List<WidgetItem> matchedWidgetItems = filterWidgetItems(
-                            input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
-                    if (matchedWidgetItems.size() > 0) {
-                        results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
-                                headerEntry.mTitleSectionName, matchedWidgetItems));
-                        results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
-                                headerEntry.mTitleSectionName, matchedWidgetItems));
-                    }
-                });
-        callback.accept(results);
-    }
-
-    private List<WidgetItem> filterWidgetItems(String query, String packageTitle,
-            List<WidgetItem> items) {
-        StringMatcher matcher = StringMatcher.getInstance();
-        if (matches(query, packageTitle, matcher)) {
-            return items;
-        }
-        return items.stream()
-                .filter(item -> matches(query, item.label, matcher))
-                .collect(Collectors.toList());
-    }
-}
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java b/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java
deleted file mode 100644
index d12782c..0000000
--- a/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java
+++ /dev/null
@@ -1,44 +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.search;
-
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * An interface for a pipeline to handle widgets search.
- */
-public interface WidgetsPickerSearchPipeline {
-
-    /**
-     * Performs a search query asynchronically. Invokes {@code callback} when the search is
-     * complete.
-     */
-    void query(String input, Consumer<List<WidgetsListBaseEntry>> callback);
-
-    /**
-     * Cancels any ongoing search request.
-     */
-    default void cancel() {};
-
-    /**
-     * Cleans up after search is no longer needed.
-     */
-    default void destroy() {};
-}
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
index 3ac82c0..0ac47ce 100644
--- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
@@ -16,9 +16,7 @@
 
 package com.android.launcher3.widget.picker.search;
 
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.List;
+import com.android.launcher3.popup.PopupDataProvider;
 
 /**
  * Interface for a widgets picker search bar.
@@ -27,7 +25,7 @@
     /**
      * Attaches a controller to the search bar which interacts with {@code searchModeListener}.
      */
-    void initialize(List<WidgetsListBaseEntry> allWidgets, SearchModeListener searchModeListener);
+    void initialize(PopupDataProvider dataProvider, SearchModeListener searchModeListener);
 
     /**
      * Clears search bar.