[search api part 1] Setup centralized SearchEventTracker

- Rename AdapterItemWIthPayload to SearchAdapterItem, PayloadResultHandler to SearchTargetHandler
- Setup SliceViewWrapper for self contained slices

Bug: 170702596
Change-Id: I0baf984ec8123c95011abcc17372f8d055e98ad7
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 75ab00a..5d5e017 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -16,7 +16,7 @@
 package com.android.launcher3.allapps;
 
 import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
-import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
+import static com.android.launcher3.allapps.AllAppsGridAdapter.SearchAdapterItem;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
@@ -57,6 +57,7 @@
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.search.SearchEventTracker;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
 import com.android.launcher3.model.data.AppInfo;
@@ -67,9 +68,7 @@
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.RecyclerViewFastScroller;
 import com.android.launcher3.views.SpringRelativeLayout;
-import com.android.systemui.plugins.shared.SearchTargetEvent;
-
-import java.util.function.IntConsumer;
+import com.android.systemui.plugins.shared.SearchTarget;
 
 /**
  * The all apps view container.
@@ -546,13 +545,9 @@
             return mLauncher.startActivitySafely(v, headerItem.getIntent(), headerItem);
         }
         AdapterItem focusedItem = getActiveRecyclerView().getApps().getFocusedChild();
-        if (focusedItem instanceof AdapterItemWithPayload) {
-            IntConsumer onSelection =
-                    ((AdapterItemWithPayload) focusedItem).getSelectionHandler();
-            if (onSelection != null) {
-                onSelection.accept(SearchTargetEvent.QUICK_SELECT);
-                return true;
-            }
+        if (focusedItem instanceof SearchAdapterItem) {
+            SearchTarget searchTarget = ((SearchAdapterItem) focusedItem).getSearchTarget();
+            SearchEventTracker.INSTANCE.get(getContext()).quickSelect(searchTarget);
         }
         if (focusedItem.appInfo != null) {
             ItemInfo itemInfo = focusedItem.appInfo;
@@ -585,6 +580,10 @@
         int padding = mHeader.getMaxTranslation();
         for (int i = 0; i < mAH.length; i++) {
             mAH[i].padding.top = padding;
+            if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mUsingTabs) {
+                //add extra space between tabs and recycler view
+                mAH[i].padding.top += mLauncher.getDeviceProfile().edgeMarginPx;
+            }
             mAH[i].applyPadding();
         }
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 8bc8e53..603e9df 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -20,8 +20,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
-import android.net.Uri;
-import android.os.Bundle;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -37,29 +35,25 @@
 import androidx.core.view.accessibility.AccessibilityEventCompat;
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
 import androidx.core.view.accessibility.AccessibilityRecordCompat;
-import androidx.lifecycle.LiveData;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
-import androidx.slice.Slice;
-import androidx.slice.widget.SliceLiveData;
 import androidx.slice.widget.SliceView;
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.search.AllAppsSearchBarController.PayloadResultHandler;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController.SearchTargetHandler;
+import com.android.launcher3.allapps.search.SearchEventTracker;
 import com.android.launcher3.allapps.search.SearchSectionInfo;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.views.HeroSearchResultView;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.launcher3.views.SearchSliceWrapper;
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
 
 import java.util.List;
-import java.util.function.IntConsumer;
 
 /**
  * The grid view adapter of all the apps.
@@ -201,28 +195,13 @@
      *
      * @param <T> Play load Type
      */
-    public static class AdapterItemWithPayload<T> extends AdapterItem {
-        private T mPayload;
+    public static class SearchAdapterItem extends AdapterItem {
+        private SearchTarget mSearchTarget;
         private String mSearchSessionId;
-        private AllAppsSearchPlugin mPlugin;
-        private IntConsumer mSelectionHandler;
 
-        public AllAppsSearchPlugin getPlugin() {
-            return mPlugin;
-        }
-
-        public void setPlugin(AllAppsSearchPlugin plugin) {
-            mPlugin = plugin;
-        }
-
-        public AdapterItemWithPayload(T payload, int type, AllAppsSearchPlugin plugin) {
-            mPayload = payload;
+        public SearchAdapterItem(SearchTarget searchTarget, int type) {
+            mSearchTarget = searchTarget;
             viewType = type;
-            mPlugin = plugin;
-        }
-
-        public void setSelectionHandler(IntConsumer runnable) {
-            mSelectionHandler = runnable;
         }
 
         public void setSearchSessionId(String searchSessionId) {
@@ -233,15 +212,9 @@
             return mSearchSessionId;
         }
 
-        public IntConsumer getSelectionHandler() {
-            return mSelectionHandler;
+        public SearchTarget getSearchTarget() {
+            return mSearchTarget;
         }
-
-        public T getPayload() {
-            return mPayload;
-        }
-
-
     }
 
     /**
@@ -492,26 +465,35 @@
                 }
                 //TODO: replace with custom TopHitBubbleTextView with support for both shortcut
                 // and apps
-                if (adapterItem instanceof AdapterItemWithPayload) {
-                    AdapterItemWithPayload item = (AdapterItemWithPayload) adapterItem;
-                    item.setSelectionHandler(type -> {
-                        SearchTargetEvent e = new SearchTargetEvent(SearchTarget.ItemType.APP,
-                                type, item.position, item.getSearchSessionId());
-                        e.bundle = HeroSearchResultView.getAppBundle(info);
-                        if (item.getPlugin() != null) {
-                            item.getPlugin().notifySearchTargetEvent(e);
+                if (adapterItem instanceof SearchAdapterItem) {
+                    SearchAdapterItem item = (SearchAdapterItem) adapterItem;
+                    SearchTargetHandler searchTargetHandler = new SearchTargetHandler() {
+                        @Override
+                        public void applySearchTarget(SearchTarget searchTarget) {
+                            // Does nothing
                         }
-                    });
+
+                        @Override
+                        public void handleSelection(int type) {
+                            SearchTargetEvent e = new SearchTargetEvent(SearchTarget.ItemType.APP,
+                                    type, item.position, item.getSearchSessionId());
+                            e.bundle = HeroSearchResultView.getAppBundle(info);
+                            SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(e);
+                        }
+                    };
+                    SearchEventTracker.INSTANCE.get(mLauncher).registerWeakHandler(
+                            ((SearchAdapterItem) adapterItem).getSearchTarget(),
+                            searchTargetHandler);
+
                     icon.setOnClickListener(view -> {
-                        item.getSelectionHandler().accept(SearchTargetEvent.SELECT);
+                        searchTargetHandler.handleSelection(SearchTargetEvent.SELECT);
                         mOnIconClickListener.onClick(view);
                     });
                     icon.setOnLongClickListener(view -> {
-                        item.getSelectionHandler().accept(SearchTargetEvent.SELECT);
+                        searchTargetHandler.handleSelection(SearchTargetEvent.LONG_PRESS);
                         return mOnIconLongClickListener.onLongClick(view);
                     });
-                }
-                else {
+                } else {
                     icon.setOnClickListener(mOnIconClickListener);
                     icon.setOnLongClickListener(mOnIconLongClickListener);
                 }
@@ -532,26 +514,12 @@
                 break;
             case VIEW_TYPE_SEARCH_SLICE:
                 SliceView sliceView = (SliceView) holder.itemView;
-                AdapterItemWithPayload<Uri> slicePayload =
-                        (AdapterItemWithPayload<Uri>) mApps.getAdapterItems().get(position);
-                sliceView.setOnSliceActionListener((info1, s) -> {
-                    if (slicePayload.getPlugin() != null) {
-                        SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
-                                SearchTarget.ItemType.SETTINGS_SLICE,
-                                SearchTargetEvent.CHILD_SELECT, slicePayload.position,
-                                slicePayload.getSearchSessionId());
-                        searchTargetEvent.bundle = new Bundle();
-                        searchTargetEvent.bundle.putParcelable("uri", slicePayload.getPayload());
-                        slicePayload.getPlugin().notifySearchTargetEvent(searchTargetEvent);
-                    }
-                });
-                try {
-                    LiveData<Slice> liveData = SliceLiveData.fromUri(mLauncher,
-                            slicePayload.getPayload());
-                    liveData.observe((Launcher) mLauncher, sliceView);
-                    sliceView.setTag(liveData);
-                } catch (Exception ignored) {
-                }
+                SearchAdapterItem slicePayload = (SearchAdapterItem) mApps.getAdapterItems().get(
+                        position);
+                SearchTarget searchTarget = slicePayload.getSearchTarget();
+                sliceView.setTag(new SearchSliceWrapper(mLauncher, sliceView, searchTarget,
+                        slicePayload.getSearchSessionId(), slicePayload.position));
+
                 break;
             case VIEW_TYPE_SEARCH_CORPUS_TITLE:
             case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON:
@@ -561,9 +529,9 @@
             case VIEW_TYPE_SEARCH_PEOPLE:
             case VIEW_TYPE_SEARCH_THUMBNAIL:
             case VIEW_TYPE_SEARCH_SUGGEST:
-                AdapterItemWithPayload item =
-                        (AdapterItemWithPayload) mApps.getAdapterItems().get(position);
-                PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;
+                SearchAdapterItem item =
+                        (SearchAdapterItem) mApps.getAdapterItems().get(position);
+                SearchTargetHandler payloadResultView = (SearchTargetHandler) holder.itemView;
                 payloadResultView.setup(item);
                 break;
             case VIEW_TYPE_ALL_APPS_DIVIDER:
@@ -582,11 +550,10 @@
             icon.setOnLongClickListener(null);
         } else if (holder.itemView instanceof SliceView) {
             SliceView sliceView = (SliceView) holder.itemView;
-            sliceView.setOnSliceActionListener(null);
-            if (sliceView.getTag() instanceof LiveData) {
-                LiveData sliceLiveData = (LiveData) sliceView.getTag();
-                sliceLiveData.removeObservers((Launcher) mLauncher);
+            if (sliceView.getTag() instanceof SearchSliceWrapper) {
+                ((SearchSliceWrapper) sliceView.getTag()).destroy();
             }
+            sliceView.setTag(null);
         }
     }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java
index eae9c0a..e2550f5 100644
--- a/src/com/android/launcher3/allapps/AllAppsPagedView.java
+++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java
@@ -25,11 +25,11 @@
 
 public class AllAppsPagedView extends PagedView<PersonalWorkSlidingTabStrip> {
 
-  final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
-  final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
-  final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
+    static final float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
+    static final float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
+    static final float TOUCH_SLOP_DAMPING_FACTOR = 4;
 
-  public AllAppsPagedView(Context context) {
+    public AllAppsPagedView(Context context) {
         this(context, null);
     }
 
@@ -42,6 +42,7 @@
         int topPadding = FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 0
                 : context.getResources().getDimensionPixelOffset(
                         R.dimen.all_apps_header_top_padding);
+        setPadding(0, topPadding, 0, 0);
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 82c4db4..6ba0421 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -31,7 +31,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.AllAppsGridAdapter;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
+import com.android.launcher3.allapps.AllAppsGridAdapter.SearchAdapterItem;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.systemui.plugins.AllAppsSearchPlugin;
@@ -211,26 +211,31 @@
      *
      * @param <T> Type of payload
      */
-    public interface PayloadResultHandler<T> {
+    public interface SearchTargetHandler {
         /**
          * Updates View using Adapter's payload
          */
 
-        default void setup(AdapterItemWithPayload<T> adapterItemWithPayload) {
+        default void setup(SearchAdapterItem searchAdapterItem) {
             Object[] targetInfo = getTargetInfo();
             if (targetInfo != null) {
-                targetInfo[0] = adapterItemWithPayload.getSearchSessionId();
-                targetInfo[1] = adapterItemWithPayload.position;
+                targetInfo[0] = searchAdapterItem.getSearchSessionId();
+                targetInfo[1] = searchAdapterItem.position;
             }
-            applyAdapterInfo(adapterItemWithPayload);
+            applySearchTarget(searchAdapterItem.getSearchTarget());
         }
 
-        void applyAdapterInfo(AdapterItemWithPayload<T> adapterItemWithPayload);
+        /**
+         * Update view using values from {@link SearchTarget}
+         */
+        void applySearchTarget(SearchTarget searchTarget);
 
         /**
-         * Gets object created by {@link PayloadResultHandler#createTargetInfo()}
+         * Gets object created by {@link SearchTargetHandler#createTargetInfo()}
          */
-        Object[] getTargetInfo();
+        default Object[] getTargetInfo() {
+            return null;
+        }
 
         /**
          * Creates a wrapper object to hold searchSessionId and item position
@@ -252,6 +257,13 @@
             return new SearchTargetEvent(itemType, eventType,
                     position, searchSessionId);
         }
+
+        /**
+         * Handles selection of SearchTarget
+         */
+        default void handleSelection(int eventType) {
+        }
+
     }
 
 
diff --git a/src/com/android/launcher3/allapps/search/SearchEventTracker.java b/src/com/android/launcher3/allapps/search/SearchEventTracker.java
new file mode 100644
index 0000000..6bcde6c
--- /dev/null
+++ b/src/com/android/launcher3/allapps/search/SearchEventTracker.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 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.allapps.search;
+
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.allapps.search.AllAppsSearchBarController.SearchTargetHandler;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+import java.util.WeakHashMap;
+
+/**
+ * A singleton class to track and report search events to search provider
+ */
+public class SearchEventTracker {
+    @Nullable
+    private AllAppsSearchPlugin mPlugin;
+    private final WeakHashMap<SearchTarget, SearchTargetHandler>
+            mCallbacks = new WeakHashMap<>();
+
+    public static final MainThreadInitializedObject<SearchEventTracker> INSTANCE =
+            new MainThreadInitializedObject<>(SearchEventTracker::new);
+
+    private SearchEventTracker(Context context) {
+    }
+
+    /**
+     * Returns instance of SearchEventTracker
+     */
+    public static SearchEventTracker getInstance(Context context) {
+        return SearchEventTracker.INSTANCE.get(context);
+    }
+
+    /**
+     * Sets current connected plugin for event reporting
+     */
+    public void setPlugin(@Nullable AllAppsSearchPlugin plugin) {
+        mPlugin = plugin;
+    }
+
+    /**
+     * Sends SearchTargetEvent to search provider
+     */
+    public void notifySearchTargetEvent(SearchTargetEvent searchTargetEvent) {
+        if (mPlugin != null) {
+            mPlugin.notifySearchTargetEvent(searchTargetEvent);
+        }
+    }
+
+    /**
+     * Registers a {@link SearchTargetHandler} to handle quick launch for specified SearchTarget.
+     */
+    public void registerWeakHandler(SearchTarget searchTarget, SearchTargetHandler targetHandler) {
+        mCallbacks.put(searchTarget, targetHandler);
+    }
+
+    /**
+     * Handles quick select for SearchTarget
+     */
+    public void quickSelect(SearchTarget searchTarget) {
+        SearchTargetHandler searchTargetHandler = mCallbacks.get(searchTarget);
+        if (searchTargetHandler != null) {
+            searchTargetHandler.handleSelection(SearchTargetEvent.QUICK_SELECT);
+        }
+    }
+
+    /**
+     * flushes all registered quick select handlers
+     */
+    public void clearHandlers() {
+        mCallbacks.clear();
+    }
+}
diff --git a/src/com/android/launcher3/views/HeroSearchResultView.java b/src/com/android/launcher3/views/HeroSearchResultView.java
index 91337ba..9e56e00 100644
--- a/src/com/android/launcher3/views/HeroSearchResultView.java
+++ b/src/com/android/launcher3/views/HeroSearchResultView.java
@@ -19,11 +19,13 @@
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ShortcutInfo;
 import android.graphics.Point;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.Pair;
 import android.view.View;
@@ -37,8 +39,9 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
-import com.android.launcher3.allapps.search.AllAppsSearchBarController.PayloadResultHandler;
+import com.android.launcher3.allapps.AllAppsStore;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController.SearchTargetHandler;
+import com.android.launcher3.allapps.search.SearchEventTracker;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.graphics.DragPreviewProvider;
@@ -48,24 +51,25 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
 import com.android.launcher3.touch.ItemLongClickListener;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.launcher3.util.ComponentKey;
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
 
-import java.util.List;
+import java.util.ArrayList;
 
 /**
  * A view representing a high confidence app search result that includes shortcuts
  */
-public class HeroSearchResultView extends LinearLayout implements DragSource,
-        PayloadResultHandler<List<Pair<ShortcutInfo, ItemInfoWithIcon>>> {
+public class HeroSearchResultView extends LinearLayout implements DragSource, SearchTargetHandler {
 
     public static final int MAX_SHORTCUTS_COUNT = 2;
+    public static final String SHORTCUTS_KEY = "shortcut_infos";
+
+
     private final Object[] mTargetInfo = createTargetInfo();
     BubbleTextView mBubbleTextView;
     View mIconView;
     BubbleTextView[] mDeepShortcutTextViews = new BubbleTextView[2];
-    AllAppsSearchPlugin mPlugin;
 
     public HeroSearchResultView(Context context) {
         super(context);
@@ -111,30 +115,35 @@
                         SearchTargetEvent.CHILD_SELECT);
                 event.bundle = getAppBundle(itemInfo);
                 event.bundle.putString("shortcut_id", itemInfo.getDeepShortcutId());
-                if (mPlugin != null) {
-                    mPlugin.notifySearchTargetEvent(event);
-                }
                 launcher.getItemOnClickListener().onClick(view);
             });
         }
     }
 
-    /**
-     * Apply {@link ItemInfo} for appIcon and shortcut Icons
-     */
     @Override
-    public void applyAdapterInfo(
-            AdapterItemWithPayload<List<Pair<ShortcutInfo, ItemInfoWithIcon>>> adapterItem) {
-        mBubbleTextView.applyFromApplicationInfo(adapterItem.appInfo);
+    public void applySearchTarget(SearchTarget searchTarget) {
+        AppInfo appInfo = getAppInfo(searchTarget.bundle);
+//        TODO: replace this with searchTarget.shortcuts
+        ArrayList<ShortcutInfo> infos = searchTarget.bundle.getParcelableArrayList(
+                SHORTCUTS_KEY);
+
+        ArrayList<Pair<ShortcutInfo, ItemInfoWithIcon>> shortcuts = new ArrayList<>();
+        for (int i = 0; infos != null && i < infos.size() && i < MAX_SHORTCUTS_COUNT; i++) {
+            ShortcutInfo shortcutInfo = infos.get(i);
+            ItemInfoWithIcon si = new WorkspaceItemInfo(shortcutInfo, getContext());
+            shortcuts.add(new Pair<>(shortcutInfo, si));
+        }
+
+
+        mBubbleTextView.applyFromApplicationInfo(appInfo);
         mIconView.setBackground(mBubbleTextView.getIcon());
-        mIconView.setTag(adapterItem.appInfo);
-        List<Pair<ShortcutInfo, ItemInfoWithIcon>> shortcutDetails = adapterItem.getPayload();
+        mIconView.setTag(appInfo);
         LauncherAppState appState = LauncherAppState.getInstance(getContext());
         for (int i = 0; i < mDeepShortcutTextViews.length; i++) {
             BubbleTextView shortcutView = mDeepShortcutTextViews[i];
-            mDeepShortcutTextViews[i].setVisibility(shortcutDetails.size() > i ? VISIBLE : GONE);
-            if (i < shortcutDetails.size()) {
-                Pair<ShortcutInfo, ItemInfoWithIcon> p = shortcutDetails.get(i);
+            mDeepShortcutTextViews[i].setVisibility(shortcuts.size() > i ? VISIBLE : GONE);
+            if (i < shortcuts.size()) {
+                Pair<ShortcutInfo, ItemInfoWithIcon> p = shortcuts.get(i);
                 //apply ItemInfo and prepare view
                 shortcutView.applyFromWorkspaceItem((WorkspaceItemInfo) p.second);
                 MODEL_EXECUTOR.execute(() -> {
@@ -144,8 +153,14 @@
                 });
             }
         }
-        mPlugin = adapterItem.getPlugin();
-        adapterItem.setSelectionHandler(this::handleSelection);
+        SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(searchTarget, this);
+    }
+
+    private AppInfo getAppInfo(Bundle bundle) {
+        AllAppsStore apps = Launcher.getLauncher(getContext()).getAppsView().getAppsStore();
+        ComponentName cn = bundle.getParcelable("component_name");
+        UserHandle userHandle = bundle.getParcelable("user_handle");
+        return (cn != null) ? apps.getApp(new ComponentKey(cn, userHandle)) : null;
     }
 
     @Override
@@ -191,15 +206,13 @@
             SearchTargetEvent event = mContainer.getSearchTargetEvent(
                     SearchTarget.ItemType.APP_HERO, SearchTargetEvent.LONG_PRESS);
             event.bundle = getAppBundle(itemInfo);
-            if (mContainer.mPlugin != null) {
-                mContainer.mPlugin.notifySearchTargetEvent(event);
-            }
-
+            SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(event);
             return false;
         }
     }
 
-    private void handleSelection(int eventType) {
+    @Override
+    public void handleSelection(int eventType) {
         ItemInfo itemInfo = (ItemInfo) mBubbleTextView.getTag();
         if (itemInfo == null) return;
         Launcher launcher = Launcher.getLauncher(getContext());
@@ -208,9 +221,7 @@
         SearchTargetEvent event = getSearchTargetEvent(
                 SearchTarget.ItemType.APP_HERO, eventType);
         event.bundle = getAppBundle(itemInfo);
-        if (mPlugin != null) {
-            mPlugin.notifySearchTargetEvent(event);
-        }
+        SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(event);
     }
 
     /**
diff --git a/src/com/android/launcher3/views/SearchResultIconRow.java b/src/com/android/launcher3/views/SearchResultIconRow.java
index 6d9c86a..ddeefaf 100644
--- a/src/com/android/launcher3/views/SearchResultIconRow.java
+++ b/src/com/android/launcher3/views/SearchResultIconRow.java
@@ -35,8 +35,8 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.allapps.search.SearchEventTracker;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.data.ItemInfo;
@@ -44,7 +44,6 @@
 import com.android.launcher3.model.data.RemoteActionItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.touch.ItemClickHandler;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTarget.ItemType;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
@@ -53,15 +52,13 @@
  * A view representing a stand alone shortcut search result
  */
 public class SearchResultIconRow extends DoubleShadowBubbleTextView implements
-        AllAppsSearchBarController.PayloadResultHandler<SearchTarget> {
+        AllAppsSearchBarController.SearchTargetHandler {
 
     private final Object[] mTargetInfo = createTargetInfo();
     private final int mCustomIconResId;
     private final boolean mMatchesInset;
 
     private ShortcutInfo mShortcutInfo;
-    private AllAppsSearchPlugin mPlugin;
-    private AdapterItemWithPayload<SearchTarget> mAdapterItem;
 
 
     public SearchResultIconRow(@NonNull Context context) {
@@ -100,26 +97,18 @@
         }
     }
 
-
     @Override
-    public void applyAdapterInfo(AdapterItemWithPayload<SearchTarget> adapterItemWithPayload) {
-        if (mAdapterItem != null) {
-            mAdapterItem.setSelectionHandler(null);
-        }
-        mAdapterItem = adapterItemWithPayload;
-        SearchTarget payload = adapterItemWithPayload.getPayload();
-        mPlugin = adapterItemWithPayload.getPlugin();
-
-        if (payload.mRemoteAction != null) {
-            prepareUsingRemoteAction(payload.mRemoteAction,
-                    payload.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
-                    payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START),
-                    payload.type == ItemType.ACTION);
+    public void applySearchTarget(SearchTarget searchTarget) {
+        if (searchTarget.mRemoteAction != null) {
+            prepareUsingRemoteAction(searchTarget.mRemoteAction,
+                    searchTarget.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
+                    searchTarget.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START),
+                    searchTarget.type == ItemType.ACTION);
         } else {
-            prepareUsingShortcutInfo(payload.shortcuts.get(0));
+            prepareUsingShortcutInfo(searchTarget.shortcuts.get(0));
         }
         setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
-        adapterItemWithPayload.setSelectionHandler(this::handleSelection);
+        SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(searchTarget, this);
     }
 
     private void prepareUsingShortcutInfo(ShortcutInfo shortcutInfo) {
@@ -179,7 +168,8 @@
         return mTargetInfo;
     }
 
-    private void handleSelection(int eventType) {
+    @Override
+    public void handleSelection(int eventType) {
         ItemInfo itemInfo = (ItemInfo) getTag();
         Launcher launcher = Launcher.getLauncher(getContext());
         final SearchTargetEvent searchTargetEvent;
@@ -200,8 +190,6 @@
             searchTargetEvent.bundle.putString(SearchTarget.REMOTE_ACTION_TOKEN,
                     remoteItemInfo.getToken());
         }
-        if (mPlugin != null) {
-            mPlugin.notifySearchTargetEvent(searchTargetEvent);
-        }
+        SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(searchTargetEvent);
     }
 }
diff --git a/src/com/android/launcher3/views/SearchResultPeopleView.java b/src/com/android/launcher3/views/SearchResultPeopleView.java
index f20b080..18bc99a 100644
--- a/src/com/android/launcher3/views/SearchResultPeopleView.java
+++ b/src/com/android/launcher3/views/SearchResultPeopleView.java
@@ -42,11 +42,10 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsGridAdapter;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.allapps.search.SearchEventTracker;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.LauncherIcons;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
 
@@ -56,7 +55,7 @@
  * A view representing a single people search result in all apps
  */
 public class SearchResultPeopleView extends LinearLayout implements
-        AllAppsSearchBarController.PayloadResultHandler<Bundle> {
+        AllAppsSearchBarController.SearchTargetHandler {
 
     private final int mIconSize;
     private final int mButtonSize;
@@ -64,7 +63,6 @@
     private View mIconView;
     private TextView mTitleView;
     private ImageButton[] mProviderButtons = new ImageButton[3];
-    private AllAppsSearchPlugin mPlugin;
     private Intent mIntent;
     private final Object[] mTargetInfo = createTargetInfo();
 
@@ -103,10 +101,8 @@
     }
 
     @Override
-    public void applyAdapterInfo(
-            AllAppsGridAdapter.AdapterItemWithPayload<Bundle> adapterItemWithPayload) {
-        Bundle payload = adapterItemWithPayload.getPayload();
-        mPlugin = adapterItemWithPayload.getPlugin();
+    public void applySearchTarget(SearchTarget searchTarget) {
+        Bundle payload = searchTarget.bundle;
         mTitleView.setText(payload.getString("title"));
         mIntent = payload.getParcelable("intent");
         Bitmap contactIcon = payload.getParcelable("icon");
@@ -125,7 +121,7 @@
             if (providers != null && i < providers.size()) {
                 Bundle provider = providers.get(i);
                 Intent intent = provider.getParcelable("intent");
-                setupProviderButton(button, provider, intent, adapterItemWithPayload);
+                setupProviderButton(button, provider, intent);
                 UI_HELPER_EXECUTOR.post(() -> {
                     String pkg = provider.getString("package_name");
                     Drawable appIcon = getAppIcon(pkg);
@@ -138,13 +134,13 @@
                 button.setVisibility(GONE);
             }
         }
-        adapterItemWithPayload.setSelectionHandler(this::handleSelection);
+        SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(searchTarget, this);
     }
 
     /**
-     *  Normalizes the bitmap to look like rounded App Icon
-     *  TODO(b/170234747) to support styling, generate adaptive icon drawable and generate
-     *  bitmap from it.
+     * Normalizes the bitmap to look like rounded App Icon
+     * TODO(b/170234747) to support styling, generate adaptive icon drawable and generate
+     * bitmap from it.
      */
     private Bitmap roundBitmap(Bitmap icon) {
         final RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon);
@@ -185,37 +181,32 @@
         return mTargetInfo;
     }
 
-    private void setupProviderButton(ImageButton button, Bundle provider, Intent intent,
-            AllAppsGridAdapter.AdapterItem adapterItem) {
+    private void setupProviderButton(ImageButton button, Bundle provider, Intent intent) {
         Launcher launcher = Launcher.getLauncher(getContext());
         button.setOnClickListener(b -> {
             launcher.startActivitySafely(b, intent, null);
-            SearchTargetEvent searchTargetEvent = getSearchTargetEvent(
+            SearchTargetEvent event = getSearchTargetEvent(
                     SearchTarget.ItemType.PEOPLE,
                     SearchTargetEvent.CHILD_SELECT);
-            searchTargetEvent.bundle = new Bundle();
-            searchTargetEvent.bundle.putParcelable("intent", intent);
-            searchTargetEvent.bundle.putString("title", mTitleView.getText().toString());
-            searchTargetEvent.bundle.putBundle("provider", provider);
-            if (mPlugin != null) {
-                mPlugin.notifySearchTargetEvent(searchTargetEvent);
-            }
+            event.bundle = new Bundle();
+            event.bundle.putParcelable("intent", intent);
+            event.bundle.putString("title", mTitleView.getText().toString());
+            event.bundle.putBundle("provider", provider);
+            SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(event);
         });
     }
 
-
-    private void handleSelection(int eventType) {
+    @Override
+    public void handleSelection(int eventType) {
         if (mIntent != null) {
             Launcher launcher = Launcher.getLauncher(getContext());
             launcher.startActivitySafely(this, mIntent, null);
-            SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.PEOPLE,
+            SearchTargetEvent event = getSearchTargetEvent(SearchTarget.ItemType.PEOPLE,
                     eventType);
-            searchTargetEvent.bundle = new Bundle();
-            searchTargetEvent.bundle.putParcelable("intent", mIntent);
-            searchTargetEvent.bundle.putString("title", mTitleView.getText().toString());
-            if (mPlugin != null) {
-                mPlugin.notifySearchTargetEvent(searchTargetEvent);
-            }
+            event.bundle = new Bundle();
+            event.bundle.putParcelable("intent", mIntent);
+            event.bundle.putString("title", mTitleView.getText().toString());
+            SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(event);
         }
     }
 }
diff --git a/src/com/android/launcher3/views/SearchResultPlayItem.java b/src/com/android/launcher3/views/SearchResultPlayItem.java
index c7133fd..39a8304 100644
--- a/src/com/android/launcher3/views/SearchResultPlayItem.java
+++ b/src/com/android/launcher3/views/SearchResultPlayItem.java
@@ -41,11 +41,10 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.allapps.search.SearchEventTracker;
 import com.android.launcher3.icons.BitmapRenderer;
 import com.android.launcher3.util.Themes;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
 
@@ -57,22 +56,19 @@
  * A View representing a PlayStore item.
  */
 public class SearchResultPlayItem extends LinearLayout implements
-        AllAppsSearchBarController.PayloadResultHandler<Bundle> {
+        AllAppsSearchBarController.SearchTargetHandler {
 
     private static final int BITMAP_CROP_MASK_COLOR = 0xff424242;
-
+    final Paint mIconPaint = new Paint();
+    final Rect mTempRect = new Rect();
     private final DeviceProfile mDeviceProfile;
+    private final Object[] mTargetInfo = createTargetInfo();
     private View mIconView;
     private TextView mTitleView;
     private TextView[] mDetailViews = new TextView[3];
     private Button mPreviewButton;
     private String mPackageName;
     private boolean mIsInstantGame;
-    private AllAppsSearchPlugin mPlugin;
-    private final Object[] mTargetInfo = createTargetInfo();
-
-    final Paint mIconPaint = new Paint();
-    final Rect mTempRect = new Rect();
 
 
     public SearchResultPlayItem(Context context) {
@@ -108,11 +104,32 @@
 
     }
 
+
+    private Bitmap getRoundedBitmap(Bitmap bitmap) {
+        final int iconSize = bitmap.getWidth();
+        final float radius = Themes.getDialogCornerRadius(getContext());
+
+        Bitmap output = BitmapRenderer.createHardwareBitmap(iconSize, iconSize, (canvas) -> {
+            mTempRect.set(0, 0, iconSize, iconSize);
+            final RectF rectF = new RectF(mTempRect);
+
+            mIconPaint.setAntiAlias(true);
+            mIconPaint.reset();
+            canvas.drawARGB(0, 0, 0, 0);
+            mIconPaint.setColor(BITMAP_CROP_MASK_COLOR);
+            canvas.drawRoundRect(rectF, radius, radius, mIconPaint);
+
+            mIconPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+            canvas.drawBitmap(bitmap, mTempRect, mTempRect, mIconPaint);
+        });
+        return output;
+    }
+
+
     @Override
-    public void applyAdapterInfo(AdapterItemWithPayload<Bundle> adapterItemWithPayload) {
-        Bundle bundle = adapterItemWithPayload.getPayload();
-        mPlugin = adapterItemWithPayload.getPlugin();
-        adapterItemWithPayload.setSelectionHandler(this::handleSelection);
+    public void applySearchTarget(SearchTarget searchTarget) {
+        Bundle bundle = searchTarget.bundle;
+        SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(searchTarget, this);
         if (bundle.getString("package", "").equals(mPackageName)) {
             return;
         }
@@ -143,28 +160,6 @@
         });
     }
 
-
-    private Bitmap getRoundedBitmap(Bitmap bitmap) {
-        final int iconSize = bitmap.getWidth();
-        final float radius = Themes.getDialogCornerRadius(getContext());
-
-        Bitmap output = BitmapRenderer.createHardwareBitmap(iconSize, iconSize, (canvas) -> {
-            mTempRect.set(0, 0, iconSize, iconSize);
-            final RectF rectF = new RectF(mTempRect);
-
-            mIconPaint.setAntiAlias(true);
-            mIconPaint.reset();
-            canvas.drawARGB(0, 0, 0, 0);
-            mIconPaint.setColor(BITMAP_CROP_MASK_COLOR);
-            canvas.drawRoundRect(rectF, radius, radius, mIconPaint);
-
-            mIconPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
-            canvas.drawBitmap(bitmap, mTempRect, mTempRect, mIconPaint);
-        });
-        return output;
-    }
-
-
     @Override
     public Object[] getTargetInfo() {
         return mTargetInfo;
@@ -179,7 +174,8 @@
         }
     }
 
-    private void handleSelection(int eventType) {
+    @Override
+    public void handleSelection(int eventType) {
         if (mPackageName == null) return;
         Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(
                 "https://play.google.com/store/apps/details?id="
@@ -209,8 +205,6 @@
                 SearchTarget.ItemType.PLAY_RESULTS, eventType);
         searchTargetEvent.bundle = new Bundle();
         searchTargetEvent.bundle.putString("package_name", mPackageName);
-        if (mPlugin != null) {
-            mPlugin.notifySearchTargetEvent(searchTargetEvent);
-        }
+        SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(searchTargetEvent);
     }
 }
diff --git a/src/com/android/launcher3/views/SearchSectionHeaderView.java b/src/com/android/launcher3/views/SearchSectionHeaderView.java
index 0fe0a43..370b921 100644
--- a/src/com/android/launcher3/views/SearchSectionHeaderView.java
+++ b/src/com/android/launcher3/views/SearchSectionHeaderView.java
@@ -21,14 +21,14 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.allapps.AllAppsGridAdapter;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.systemui.plugins.shared.SearchTarget;
 
 /**
  * Header text view that shows a title for a given section in All apps search
  */
 public class SearchSectionHeaderView extends TextView implements
-        AllAppsSearchBarController.PayloadResultHandler<String> {
+        AllAppsSearchBarController.SearchTargetHandler {
     public SearchSectionHeaderView(Context context) {
         super(context);
     }
@@ -43,8 +43,8 @@
     }
 
     @Override
-    public void applyAdapterInfo(AllAppsGridAdapter.AdapterItemWithPayload<String> adapterItem) {
-        String title = adapterItem.getPayload();
+    public void applySearchTarget(SearchTarget searchTarget) {
+        String title = searchTarget.type.getTitle();
         if (title == null || !title.isEmpty()) {
             setText(title);
             setVisibility(VISIBLE);
diff --git a/src/com/android/launcher3/views/SearchSettingsRowView.java b/src/com/android/launcher3/views/SearchSettingsRowView.java
index a1a0172..ac69548 100644
--- a/src/com/android/launcher3/views/SearchSettingsRowView.java
+++ b/src/com/android/launcher3/views/SearchSettingsRowView.java
@@ -29,9 +29,8 @@
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsGridAdapter;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.launcher3.allapps.search.SearchEventTracker;
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
 
@@ -41,13 +40,12 @@
  * A row of tappable TextViews with a breadcrumb for settings search.
  */
 public class SearchSettingsRowView extends LinearLayout implements
-        View.OnClickListener, AllAppsSearchBarController.PayloadResultHandler<Bundle> {
+        View.OnClickListener, AllAppsSearchBarController.SearchTargetHandler {
 
     private TextView mTitleView;
     private TextView mDescriptionView;
     private TextView mBreadcrumbsView;
     private Intent mIntent;
-    private AllAppsSearchPlugin mPlugin;
     private final Object[] mTargetInfo = createTargetInfo();
 
 
@@ -75,10 +73,8 @@
     }
 
     @Override
-    public void applyAdapterInfo(
-            AllAppsGridAdapter.AdapterItemWithPayload<Bundle> adapterItemWithPayload) {
-        Bundle bundle = adapterItemWithPayload.getPayload();
-        mPlugin = adapterItemWithPayload.getPlugin();
+    public void applySearchTarget(SearchTarget searchTarget) {
+        Bundle bundle = searchTarget.bundle;
         mIntent = bundle.getParcelable("intent");
         showIfAvailable(mTitleView, bundle.getString("title"));
         showIfAvailable(mDescriptionView, bundle.getString("description"));
@@ -86,7 +82,7 @@
         //TODO: implement RTL friendly breadcrumbs view
         showIfAvailable(mBreadcrumbsView, breadcrumbs != null
                 ? String.join(" > ", breadcrumbs) : null);
-        adapterItemWithPayload.setSelectionHandler(this::handleSelection);
+        SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(searchTarget, this);
     }
 
     @Override
@@ -108,7 +104,8 @@
         handleSelection(SearchTargetEvent.SELECT);
     }
 
-    private void handleSelection(int eventType) {
+    @Override
+    public void handleSelection(int eventType) {
         if (mIntent == null) return;
         // TODO: create ItemInfo object and then use it to call startActivityForResult for proper
         //  WW logging
@@ -119,8 +116,6 @@
                 SearchTarget.ItemType.SETTINGS_ROW, eventType);
         searchTargetEvent.bundle = new Bundle();
         searchTargetEvent.bundle.putParcelable("intent", mIntent);
-        if (mPlugin != null) {
-            mPlugin.notifySearchTargetEvent(searchTargetEvent);
-        }
+        SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(searchTargetEvent);
     }
 }
diff --git a/src/com/android/launcher3/views/SearchSliceWrapper.java b/src/com/android/launcher3/views/SearchSliceWrapper.java
new file mode 100644
index 0000000..b088237
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchSliceWrapper.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.views;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.widget.EventInfo;
+import androidx.slice.widget.SliceLiveData;
+import androidx.slice.widget.SliceView;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.allapps.search.SearchEventTracker;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+/**
+ * A Wrapper class for {@link SliceView} search results
+ */
+public class SearchSliceWrapper implements SliceView.OnSliceActionListener {
+
+    private static final String TAG = "SearchSliceController";
+    private static final String URI_EXTRA_KEY = "slice_uri";
+
+
+    private final Launcher mLauncher;
+    private final SearchTarget mSearchTarget;
+    private final SliceView mSliceView;
+    //TODO: remove these as we move to tracking search results individually with unique ID
+    private final int mPosition;
+    private final String mSessionId;
+    private LiveData<Slice> mSliceLiveData;
+
+    public SearchSliceWrapper(Context context, SliceView sliceView,
+            SearchTarget searchTarget, String sessionId, int position) {
+        mLauncher = Launcher.getLauncher(context);
+        mPosition = position;
+        mSessionId = sessionId;
+        mSearchTarget = searchTarget;
+        mSliceView = sliceView;
+        sliceView.setOnSliceActionListener(this);
+        try {
+            mSliceLiveData = SliceLiveData.fromUri(mLauncher, getSliceUri());
+            mSliceLiveData.observe((Launcher) mLauncher, sliceView);
+        } catch (Exception ex) {
+            Log.e(TAG, "unable to bind slice", ex);
+        }
+    }
+
+    /**
+     * Unregisters event handlers and removes lifecycle observer
+     */
+    public void destroy() {
+        mSliceView.setOnSliceActionListener(null);
+        mSliceLiveData.removeObservers(mLauncher);
+    }
+
+    @Override
+    public void onSliceAction(@NonNull EventInfo info, @NonNull SliceItem item) {
+        SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
+                SearchTarget.ItemType.SETTINGS_SLICE,
+                SearchTargetEvent.CHILD_SELECT, mPosition,
+                mSessionId);
+        searchTargetEvent.bundle = new Bundle();
+        searchTargetEvent.bundle.putParcelable(URI_EXTRA_KEY, getSliceUri());
+        SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(searchTargetEvent);
+    }
+
+    private Uri getSliceUri() {
+        return mSearchTarget.bundle.getParcelable(URI_EXTRA_KEY);
+    }
+}
diff --git a/src/com/android/launcher3/views/ThumbnailSearchResultView.java b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
index 81bcad9..2121232 100644
--- a/src/com/android/launcher3/views/ThumbnailSearchResultView.java
+++ b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
@@ -26,14 +26,13 @@
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
 
 import com.android.launcher3.Launcher;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.allapps.search.SearchEventTracker;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.RemoteActionItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.util.Themes;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
 
@@ -41,11 +40,9 @@
  * A view representing a high confidence app search result that includes shortcuts
  */
 public class ThumbnailSearchResultView extends androidx.appcompat.widget.AppCompatImageView
-        implements AllAppsSearchBarController.PayloadResultHandler<SearchTarget> {
+        implements AllAppsSearchBarController.SearchTargetHandler {
 
     private final Object[] mTargetInfo = createTargetInfo();
-    AllAppsSearchPlugin mPlugin;
-    int mPosition;
 
     public ThumbnailSearchResultView(Context context) {
         super(context);
@@ -59,7 +56,8 @@
         super(context, attrs, defStyleAttr);
     }
 
-    private void handleSelection(int eventType) {
+    @Override
+    public void handleSelection(int eventType) {
         Launcher launcher = Launcher.getLauncher(getContext());
         ItemInfo itemInfo = (ItemInfo) getTag();
         if (itemInfo instanceof RemoteActionItemInfo) {
@@ -68,26 +66,19 @@
         } else {
             ItemClickHandler.onClickAppShortcut(this, (WorkspaceItemInfo) itemInfo, launcher);
         }
-        if (mPlugin != null) {
-            SearchTargetEvent event = getSearchTargetEvent(
-                    SearchTarget.ItemType.SCREENSHOT, eventType);
-            mPlugin.notifySearchTargetEvent(event);
-        }
+        SearchTargetEvent e = getSearchTargetEvent(SearchTarget.ItemType.SCREENSHOT, eventType);
+        SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(e);
     }
 
     @Override
-    public void applyAdapterInfo(AdapterItemWithPayload<SearchTarget> adapterItem) {
-        Launcher launcher = Launcher.getLauncher(getContext());
-        mPosition = adapterItem.position;
-
-        SearchTarget target = adapterItem.getPayload();
+    public void applySearchTarget(SearchTarget target) {
         Bitmap bitmap;
         if (target.mRemoteAction != null) {
             RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(target.mRemoteAction,
                     target.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
                     target.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
             bitmap = ((BitmapDrawable) target.mRemoteAction.getIcon()
-                .loadDrawable(getContext())).getBitmap();
+                    .loadDrawable(getContext())).getBitmap();
             Bitmap crop = Bitmap.createBitmap(bitmap, 0,
                     bitmap.getHeight() / 2 - bitmap.getWidth() / 2,
                     bitmap.getWidth(), bitmap.getWidth());
@@ -106,8 +97,7 @@
         drawable.setCornerRadius(Themes.getDialogCornerRadius(getContext()));
         setImageDrawable(drawable);
         setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
-        mPlugin = adapterItem.getPlugin();
-        adapterItem.setSelectionHandler(this::handleSelection);
+        SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(target, this);
     }
 
     @Override