Replacing ItemInfoMatcher with predicate

This removed unnecessary componentName lookups when it
is not required. Many checks just rely on IDs and
userHandle

Bug: 231153610
Test: Presubmit
Change-Id: Ief93954abc5861062a9f55dc2ef181d3de106c62
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 62a8da7..05b8167 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -55,13 +55,13 @@
 import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.uioverrides.PredictedAppIcon;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.launcher3.views.Snackbar;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 /**
@@ -480,8 +480,8 @@
      *
      * @param matcher filter matching items that have been removed
      */
-    public void onModelItemsRemoved(ItemInfoMatcher matcher) {
-        if (mPredictedItems.removeIf(matcher::matchesInfo)) {
+    public void onModelItemsRemoved(Predicate<ItemInfo> matcher) {
+        if (mPredictedItems.removeIf(matcher)) {
             fillGapsWithPrediction(true);
         }
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 5c10565..c522888 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -73,6 +73,7 @@
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.function.Predicate;
 
 /**
  * Handles long click on Taskbar items to start a system drag and drop operation.
@@ -439,12 +440,12 @@
                 target = taskbarViewController.getAllAppsButtonView();
             } else if (item.container >= 0) {
                 // Since folders close when the drag starts, target the folder icon instead.
-                ItemInfoMatcher matcher = ItemInfoMatcher.forFolderMatch(
+                Predicate<ItemInfo> matcher = ItemInfoMatcher.forFolderMatch(
                         ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id)));
                 target = taskbarViewController.getFirstIconMatch(matcher);
             } else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
                 // Find first icon with same package/user as the deep shortcut.
-                ItemInfoMatcher packageUserMatcher = ItemInfoMatcher.ofPackages(
+                Predicate<ItemInfo> packageUserMatcher = ItemInfoMatcher.ofPackages(
                         Collections.singleton(item.getTargetPackage()), item.user);
                 target = taskbarViewController.getFirstIconMatch(packageUserMatcher);
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 62392ee..75881a3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -36,6 +36,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Launcher model Callbacks for rendering taskbar.
@@ -126,16 +127,16 @@
     }
 
     @Override
-    public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
+    public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
         if (handleItemsRemoved(matcher)) {
             commitItemsToUI();
         }
     }
 
-    private boolean handleItemsRemoved(ItemInfoMatcher matcher) {
+    private boolean handleItemsRemoved(Predicate<ItemInfo> matcher) {
         boolean modified = false;
         for (int i = mHotseatItems.size() - 1; i >= 0; i--) {
-            if (matcher.matchesInfo(mHotseatItems.valueAt(i))) {
+            if (matcher.test(mHotseatItems.valueAt(i))) {
                 modified = true;
                 mHotseatItems.removeAt(i);
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 7548398..6f88d64 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -41,12 +41,13 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.uioverrides.ApiWrapper;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.AllAppsButton;
 import com.android.launcher3.views.DoubleShadowBubbleTextView;
 
+import java.util.function.Predicate;
+
 /**
  * Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
  */
@@ -424,8 +425,8 @@
      * Finds the first icon to match one of the given matchers, from highest to lowest priority.
      * @return The first match, or All Apps button if no match was found.
      */
-    public View getFirstMatch(ItemInfoMatcher... matchers) {
-        for (ItemInfoMatcher matcher : matchers) {
+    public View getFirstMatch(Predicate<ItemInfo>... matchers) {
+        for (Predicate<ItemInfo> matcher : matchers) {
             for (int i = 0; i < getChildCount(); i++) {
                 View item = getChildAt(i);
                 if (!(item.getTag() instanceof ItemInfo)) {
@@ -433,7 +434,7 @@
                     continue;
                 }
                 ItemInfo info = (ItemInfo) item.getTag();
-                if (matcher.matchesInfo(info)) {
+                if (matcher.test(info)) {
                     return item;
                 }
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 6416720..0cc3590 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -47,6 +47,7 @@
 import com.android.quickstep.AnimatedFloat;
 
 import java.io.PrintWriter;
+import java.util.function.Predicate;
 
 /**
  * Handles properties/data collection, then passes the results to TaskbarView to render.
@@ -309,8 +310,8 @@
      * 2) FolderIcon of the Folder containing the given icon
      * 3) All Apps button
      */
-    public View getFirstIconMatch(ItemInfoMatcher matcher) {
-        ItemInfoMatcher folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
+    public View getFirstIconMatch(Predicate<ItemInfo> matcher) {
+        Predicate<ItemInfo> folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
         return mTaskbarView.getFirstMatch(matcher, folderMatcher);
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 7c52e80..4bb4343 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -70,7 +70,6 @@
 import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.NavigationMode;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.PendingRequestArgs;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.util.UiThreadHelper;
@@ -86,6 +85,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Objects;
+import java.util.function.Predicate;
 import java.util.stream.Stream;
 
 public class QuickstepLauncher extends BaseQuickstepLauncher {
@@ -245,7 +245,7 @@
     }
 
     @Override
-    public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
+    public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
         super.bindWorkspaceComponentsRemoved(matcher);
         mHotseatPredictionController.onModelItemsRemoved(matcher);
     }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4b42ecb..3164db2 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -182,7 +182,6 @@
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
@@ -2739,9 +2738,9 @@
      */
     public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user,
             boolean supportsAllAppsState) {
-        final ItemInfoMatcher preferredItem = (info, cn) ->
+        final Predicate<ItemInfo> preferredItem = info ->
                 info != null && info.id == preferredItemId;
-        final ItemInfoMatcher packageAndUserAndApp = (info, cn) ->
+        final Predicate<ItemInfo> packageAndUserAndApp = info ->
                 info != null
                         && info.itemType == ITEM_TYPE_APPLICATION
                         && info.user.equals(user)
@@ -2770,8 +2769,8 @@
      * @param operators List of operators, in order starting from best matching operator.
      */
     private static View getFirstMatch(Iterable<ViewGroup> containers,
-            final ItemInfoMatcher... operators) {
-        for (ItemInfoMatcher operator : operators) {
+            final Predicate<ItemInfo>... operators) {
+        for (Predicate<ItemInfo> operator : operators) {
             for (ViewGroup container : containers) {
                 View match = mapOverViewGroup(container, operator);
                 if (match != null) {
@@ -2786,11 +2785,11 @@
      * Returns the first view matching the operator in the given ViewGroups, or null if none.
      * Forward iteration matters.
      */
-    private static View mapOverViewGroup(ViewGroup container, ItemInfoMatcher op) {
+    private static View mapOverViewGroup(ViewGroup container, Predicate<ItemInfo> op) {
         final int itemCount = container.getChildCount();
         for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
             View item = container.getChildAt(itemIdx);
-            if (op.matchesInfo((ItemInfo) item.getTag())) {
+            if (op.test((ItemInfo) item.getTag())) {
                 return item;
             }
         }
@@ -2887,7 +2886,7 @@
      * package-removal should clear all items by package name.
      */
     @Override
-    public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) {
+    public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
         mWorkspace.removeItemsByMatcher(matcher);
         mDragController.onAppsRemoved(matcher);
         PopupContainerWithArrow.dismissInvalidPopup(this);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 78771ce..14320eb 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -102,7 +102,6 @@
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.IntSparseArrayMap;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.util.OverlayEdgeEffect;
 import com.android.launcher3.util.PackageUserKey;
@@ -3235,7 +3234,7 @@
      * as a part of an update, this is called to ensure that other widgets and application
      * shortcuts are not removed.
      */
-    public void removeItemsByMatcher(final ItemInfoMatcher matcher) {
+    public void removeItemsByMatcher(final Predicate<ItemInfo> matcher) {
         for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
             ShortcutAndWidgetContainer container = layout.getShortcutsAndWidgets();
             // Iterate in reverse order as we are removing items
@@ -3243,7 +3242,7 @@
                 View child = container.getChildAt(i);
                 ItemInfo info = (ItemInfo) child.getTag();
 
-                if (matcher.matchesInfo(info)) {
+                if (matcher.test(info)) {
                     layout.removeViewInLayout(child);
                     if (child instanceof DropTarget) {
                         mDragController.removeDropTarget((DropTarget) child);
@@ -3251,7 +3250,7 @@
                 } else if (child instanceof FolderIcon) {
                     FolderInfo folderInfo = (FolderInfo) info;
                     List<WorkspaceItemInfo> matches = folderInfo.contents.stream()
-                            .filter(matcher::matchesInfo)
+                            .filter(matcher)
                             .collect(Collectors.toList());
                     if (!matches.isEmpty()) {
                         folderInfo.removeAll(matches, false);
@@ -3330,7 +3329,7 @@
      *
      * @param matcher  the matcher generated by the caller.
      */
-    public void persistRemoveItemsByMatcher(ItemInfoMatcher matcher) {
+    public void persistRemoveItemsByMatcher(Predicate<ItemInfo> matcher) {
         mLauncher.getModelWriter().deleteItemsFromDatabase(matcher);
         removeItemsByMatcher(matcher);
     }
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 2a16210..cdaf80a 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -21,17 +21,18 @@
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.LabelComparator;
 import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Objects;
 import java.util.TreeMap;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * The alphabetically sorted list of applications.
@@ -82,7 +83,7 @@
     private AppInfoComparator mAppNameComparator;
     private final int mNumAppsPerRowAllApps;
     private int mNumAppRowsInAdapter;
-    private ItemInfoMatcher mItemFilter;
+    private Predicate<ItemInfo> mItemFilter;
 
     public AlphabeticalAppsList(Context context, AllAppsStore appsStore,
             WorkAdapterProvider adapterProvider) {
@@ -94,7 +95,7 @@
         mAllAppsStore.addUpdateListener(this);
     }
 
-    public void updateItemFilter(ItemInfoMatcher itemFilter) {
+    public void updateItemFilter(Predicate<ItemInfo> itemFilter) {
         this.mItemFilter = itemFilter;
         onAppsUpdated();
     }
@@ -200,13 +201,11 @@
         // Sort the list of apps
         mApps.clear();
 
-        for (AppInfo app : mAllAppsStore.getApps()) {
-            if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) {
-                mApps.add(app);
-            }
+        Stream<AppInfo> appSteam = Stream.of(mAllAppsStore.getApps());
+        if (!hasFilter() && mItemFilter != null) {
+            appSteam = appSteam.filter(mItemFilter);
         }
-
-        Collections.sort(mApps, mAppNameComparator);
+        appSteam = appSteam.sorted(mAppNameComparator);
 
         // As a special case for some languages (currently only Simplified Chinese), we may need to
         // coalesce sections
@@ -215,27 +214,16 @@
         if (localeRequiresSectionSorting) {
             // Compute the section headers. We use a TreeMap with the section name comparator to
             // ensure that the sections are ordered when we iterate over it later
-            TreeMap<String, ArrayList<AppInfo>> sectionMap = new TreeMap<>(new LabelComparator());
-            for (AppInfo info : mApps) {
-                // Add the section to the cache
-                String sectionName = info.sectionName;
-
-                // Add it to the mapping
-                ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
-                if (sectionApps == null) {
-                    sectionApps = new ArrayList<>();
-                    sectionMap.put(sectionName, sectionApps);
-                }
-                sectionApps.add(info);
-            }
-
-            // Add each of the section apps to the list in order
-            mApps.clear();
-            for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
-                mApps.addAll(entry.getValue());
-            }
+            appSteam = appSteam.collect(Collectors.groupingBy(
+                    info -> info.sectionName,
+                    () -> new TreeMap<>(new LabelComparator()),
+                    Collectors.toCollection(ArrayList::new)))
+                    .values()
+                    .stream()
+                    .flatMap(ArrayList::stream);
         }
 
+        appSteam.forEachOrdered(mApps::add);
         // Recompose the set of adapter items from the current set of apps
         if (mSearchResults.isEmpty()) {
             updateAdapterItems();
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index f913aa9..891fe8f 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -58,7 +58,7 @@
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
 import com.android.launcher3.model.StringCache;
-import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
@@ -69,6 +69,8 @@
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 /**
  * Base all apps view container.
@@ -91,7 +93,7 @@
     /** Context of an activity or window that is inflating this container. */
     protected final T mActivityContext;
     protected final List<AdapterHolder> mAH;
-    protected final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(
+    protected final Predicate<ItemInfo> mPersonalMatcher = ItemInfoMatcher.ofUser(
             Process.myUserHandle());
     private final SearchAdapterProvider<?> mMainAdapterProvider;
     private final AllAppsStore mAllAppsStore = new AllAppsStore();
@@ -229,17 +231,10 @@
     }
 
     private void onAppsUpdated() {
-        boolean hasWorkApps = false;
-        for (AppInfo app : mAllAppsStore.getApps()) {
-            if (mWorkManager.getMatcher().matches(app, null)) {
-                hasWorkApps = true;
-                break;
-            }
-        }
-        mHasWorkApps = hasWorkApps;
+        mHasWorkApps = Stream.of(mAllAppsStore.getApps()).anyMatch(mWorkManager.getMatcher());
         if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasFilter()) {
             rebindAdapters();
-            if (hasWorkApps) {
+            if (mHasWorkApps) {
                 mWorkManager.reset();
             }
         }
@@ -731,7 +726,7 @@
             mLayoutManager = adapter.getLayoutManager();
         }
 
-        void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
+        void setup(@NonNull View rv, @Nullable Predicate<ItemInfo> matcher) {
             mAppsList.updateItemFilter(matcher);
             mRecyclerView = (AllAppsRecyclerView) rv;
             mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 6203cea..c5b02dd 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -27,7 +27,6 @@
 import android.os.UserManager;
 import android.util.Log;
 import android.view.ViewGroup;
-import android.view.WindowInsets;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
@@ -35,11 +34,12 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.function.Predicate;
 
 /**
  * Companion class for {@link BaseAllAppsContainerView} to manage work tab and personal tab
@@ -70,7 +70,7 @@
 
     private final BaseAllAppsContainerView<?> mAllApps;
     private final WorkAdapterProvider mAdapterProvider;
-    private final ItemInfoMatcher mMatcher;
+    private final Predicate<ItemInfo> mMatcher;
 
     private WorkModeSwitch mWorkModeSwitch;
 
@@ -176,7 +176,7 @@
         return mAdapterProvider;
     }
 
-    public ItemInfoMatcher getMatcher() {
+    public Predicate<ItemInfo> getMatcher() {
         return mMatcher;
     }
 
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index fdb2799..35cdfef 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -18,7 +18,6 @@
 
 import static com.android.launcher3.Utilities.ATLEAST_Q;
 
-import android.content.ComponentName;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -36,12 +35,12 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
 import java.util.Optional;
+import java.util.function.Predicate;
 
 /**
  * Class for initiating a drag within a view or across multiple views.
@@ -275,15 +274,12 @@
 
     protected abstract void exitDrag();
 
-    public void onAppsRemoved(ItemInfoMatcher matcher) {
+    public void onAppsRemoved(Predicate<ItemInfo> matcher) {
         // Cancel the current drag if we are removing an app that we are dragging
         if (mDragObject != null) {
             ItemInfo dragInfo = mDragObject.dragInfo;
-            if (dragInfo instanceof WorkspaceItemInfo) {
-                ComponentName cn = dragInfo.getTargetComponent();
-                if (cn != null && matcher.matches(dragInfo, cn)) {
-                    cancelDrag();
-                }
+            if (dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo)) {
+                cancelDrag();
             }
         }
     }
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index b8c9762..4875d83 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -36,9 +36,9 @@
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.util.FlagOp;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.SafeCloseable;
 
@@ -47,6 +47,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 
 /**
@@ -257,11 +258,11 @@
     /**
      * Updates the disabled flags of apps matching {@param matcher} based on {@param op}.
      */
-    public void updateDisabledFlags(ItemInfoMatcher matcher, FlagOp op) {
+    public void updateDisabledFlags(Predicate<ItemInfo> matcher, FlagOp op) {
         final List<AppInfo> data = this.data;
         for (int i = data.size() - 1; i >= 0; i--) {
             AppInfo info = data.get(i);
-            if (matcher.matches(info, info.componentName)) {
+            if (matcher.test(info)) {
                 info.runtimeStatusFlags = op.apply(info.runtimeStatusFlags);
                 mDataChanged = true;
             }
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
index a3a4717..832c1dd 100644
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java
@@ -27,7 +27,6 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 
 import java.util.ArrayList;
@@ -35,6 +34,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 /**
@@ -128,7 +128,7 @@
         scheduleCallbackTask(c -> c.bindAllWidgets(widgets));
     }
 
-    public void deleteAndBindComponentsRemoved(final ItemInfoMatcher matcher) {
+    public void deleteAndBindComponentsRemoved(final Predicate<ItemInfo> matcher) {
         getModelWriter().deleteItemsFromDatabase(matcher);
 
         // Call the components-removed callback
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 866d18a..d52537e 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -50,7 +50,6 @@
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.IntSparseArrayMap;
-import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 
@@ -66,6 +65,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -495,7 +495,7 @@
         default void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) { }
         default void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) { }
         default void bindRestoreItemsChange(HashSet<ItemInfo> updates) { }
-        default void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) { }
+        default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
         default void bindAllWidgets(List<WidgetsListBaseEntry> widgets) { }
 
         default void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks) {
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 94e06d1..015abe9 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -53,6 +53,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
@@ -278,10 +279,9 @@
     /**
      * Removes all the items from the database matching {@param matcher}.
      */
-    public void deleteItemsFromDatabase(ItemInfoMatcher matcher) {
+    public void deleteItemsFromDatabase(Predicate<ItemInfo> matcher) {
         deleteItemsFromDatabase(StreamSupport.stream(mBgDataModel.itemsIdMap.spliterator(), false)
-                        .filter(matcher::matchesInfo)
-                        .collect(Collectors.toList()));
+                        .filter(matcher).collect(Collectors.toList()));
     }
 
     /**
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index d47edff..239dd45 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -57,6 +57,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Handles updates due to changes in package manager (app installed/updated/removed)
@@ -95,7 +96,7 @@
         final int N = packages.length;
         final FlagOp flagOp;
         final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
-        final ItemInfoMatcher matcher = mOp == OP_USER_AVAILABILITY_CHANGE
+        final Predicate<ItemInfo> matcher = mOp == OP_USER_AVAILABILITY_CHANGE
                 ? ItemInfoMatcher.ofUser(mUser) // We want to update all packages for this user
                 : ItemInfoMatcher.ofPackages(packageSet, mUser);
         final HashSet<ComponentName> removedComponents = new HashSet<>();
@@ -206,7 +207,7 @@
                     }
 
                     ComponentName cn = si.getTargetComponent();
-                    if (cn != null && matcher.matches(si, cn)) {
+                    if (cn != null && matcher.test(si)) {
                         String packageName = cn.getPackageName();
 
                         if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
@@ -336,7 +337,7 @@
         }
 
         if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
-            ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
+            Predicate<ItemInfo> removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
                     .or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
                     .and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
             deleteAndBindComponentsRemoved(removeMatch);
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index 7917410..b6af314 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -19,6 +19,8 @@
 import android.content.ComponentName;
 import android.os.UserHandle;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
@@ -27,90 +29,64 @@
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.function.Predicate;
 
 /**
  * A utility class to check for {@link ItemInfo}
  */
-public interface ItemInfoMatcher {
+public abstract class ItemInfoMatcher {
 
     /**
      * Empty component used for match testing
      */
-    ComponentName EMPTY_COMPONENT = new ComponentName("", "");
+    private static final ComponentName EMPTY_COMPONENT = new ComponentName("", "");
 
-    boolean matches(ItemInfo info, ComponentName cn);
-
-    /**
-     * Returns true if the itemInfo matches this check
-     */
-    default boolean matchesInfo(ItemInfo info) {
-        if (info != null) {
-            ComponentName cn = info.getTargetComponent();
-            return matches(info, cn != null ? cn : EMPTY_COMPONENT);
-        } else {
-            return false;
-        }
+    public static Predicate<ItemInfo> ofUser(UserHandle user) {
+        return info -> info != null && info.user.equals(user);
     }
 
-    /**
-     * Returns a new matcher with returns true if either this or {@param matcher} returns true.
-     */
-    default ItemInfoMatcher or(ItemInfoMatcher matcher) {
-        return (info, cn) -> matches(info, cn) || matcher.matches(info, cn);
+    public static Predicate<ItemInfo> ofComponents(
+            HashSet<ComponentName> components, UserHandle user) {
+        return info -> info != null && info.user.equals(user)
+                && components.contains(getNonNullComponent(info));
     }
 
-    /**
-     * Returns a new matcher with returns true if both this and {@param matcher} returns true.
-     */
-    default ItemInfoMatcher and(ItemInfoMatcher matcher) {
-        return (info, cn) -> matches(info, cn) && matcher.matches(info, cn);
+    public static Predicate<ItemInfo> ofPackages(Set<String> packageNames, UserHandle user) {
+        return info -> info != null && info.user.equals(user)
+                && packageNames.contains(getNonNullComponent(info).getPackageName());
     }
 
-    /**
-     * Returns a new matcher with returns the opposite value of this.
-     */
-    default ItemInfoMatcher negate() {
-        return (info, cn) -> !matches(info, cn);
-    }
-
-    static ItemInfoMatcher ofUser(UserHandle user) {
-        return (info, cn) -> info.user.equals(user);
-    }
-
-    static ItemInfoMatcher ofComponents(HashSet<ComponentName> components, UserHandle user) {
-        return (info, cn) -> components.contains(cn) && info.user.equals(user);
-    }
-
-    static ItemInfoMatcher ofPackages(Set<String> packageNames, UserHandle user) {
-        return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
-    }
-
-    static ItemInfoMatcher ofShortcutKeys(Set<ShortcutKey> keys) {
-        return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
+    public static Predicate<ItemInfo> ofShortcutKeys(Set<ShortcutKey> keys) {
+        return info -> info != null && info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
                 && keys.contains(ShortcutKey.fromItemInfo(info));
     }
 
     /**
      * Returns a matcher for items within folders.
      */
-    static ItemInfoMatcher forFolderMatch(ItemInfoMatcher childOperator) {
-        return (info, cn) -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
-                .anyMatch(childOperator::matchesInfo);
+    public static Predicate<ItemInfo> forFolderMatch(Predicate<ItemInfo> childOperator) {
+        return info -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
+                .anyMatch(childOperator);
     }
 
     /**
      * Returns a matcher for items with provided ids
      */
-    static ItemInfoMatcher ofItemIds(IntSet ids) {
-        return (info, cn) -> ids.contains(info.id);
+    public static Predicate<ItemInfo> ofItemIds(IntSet ids) {
+        return info -> info != null && ids.contains(info.id);
     }
 
     /**
      * Returns a matcher for items with provided items
      */
-    static ItemInfoMatcher ofItems(Collection<? extends ItemInfo> items) {
+    public static Predicate<ItemInfo> ofItems(Collection<? extends ItemInfo> items) {
         IntSet ids = new IntSet();
         items.forEach(item -> ids.add(item.id));
         return ofItemIds(ids);
     }
+
+    private static ComponentName getNonNullComponent(@NonNull ItemInfo info) {
+        ComponentName cn = info.getTargetComponent();
+        return cn != null ? cn : EMPTY_COMPONENT;
+    }
 }