Merge "Make keyguard exit animation to remote animation."
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 9e76ce3..4fd2e40 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -141,7 +141,7 @@
         TODO: Add proper permissions
         -->
         <provider
-            android:name="com.android.launcher3.graphics.GridOptionsProvider"
+            android:name="com.android.launcher3.graphics.GridCustomizationsProvider"
             android:authorities="${packageName}.grid_control"
             android:exported="true" />
 
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index d95cc01..9c14b85 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -31,6 +31,15 @@
     <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
     <uses-permission android:name="android.permission.VIBRATE"/>
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+    <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS"/>
+    <uses-permission android:name="android.permission.REMOVE_TASKS"/>
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
+    <uses-permission android:name="android.permission.STATUS_BAR"/>
+    <uses-permission android:name="android.permission.STOP_APP_SWITCHES"/>
+    <uses-permission android:name="android.permission.SET_ORIENTATION"/>
+    <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
+    <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY"/>
+
     <uses-permission android:name="${packageName}.permission.HOTSEAT_EDU" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
 
diff --git a/quickstep/res/layout/search_result_icon_row.xml b/quickstep/res/layout/search_result_icon_row.xml
index 2119fc3..81190cf 100644
--- a/quickstep/res/layout/search_result_icon_row.xml
+++ b/quickstep/res/layout/search_result_icon_row.xml
@@ -57,9 +57,10 @@
         style="@style/BaseIcon"
         android:layout_width="@dimen/deep_shortcut_icon_size"
         android:layout_height="match_parent"
-        android:gravity="start|center_vertical"
+        android:layout_marginStart="4dp"
+        android:gravity="center"
         launcher:iconDisplay="shortcut_popup"
-        android:textSize="@dimen/search_hero_subtitle_size"
+        android:textSize="@dimen/search_hero_inline_button_size"
         launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size"
         launcher:layoutHorizontal="false" />
 
@@ -68,6 +69,20 @@
         style="@style/BaseIcon"
         android:layout_width="@dimen/deep_shortcut_icon_size"
         android:layout_height="match_parent"
+        android:layout_marginStart="4dp"
+        android:gravity="center"
+        launcher:iconDisplay="shortcut_popup"
+        android:textSize="@dimen/search_hero_inline_button_size"
+        launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size"
+        launcher:layoutHorizontal="false" />
+
+    <com.android.launcher3.search.SearchResultIcon
+        android:id="@+id/shortcut_2"
+        style="@style/BaseIcon"
+        android:layout_width="@dimen/deep_shortcut_icon_size"
+        android:layout_height="match_parent"
+        android:layout_marginStart="4dp"
+        android:gravity="center"
         launcher:iconDisplay="shortcut_popup"
         android:textSize="@dimen/search_hero_inline_button_size"
         launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size"
diff --git a/quickstep/res/layout/search_result_people_item.xml b/quickstep/res/layout/search_result_people_item.xml
deleted file mode 100644
index 964300d..0000000
--- a/quickstep/res/layout/search_result_people_item.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- 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.
--->
-<com.android.launcher3.search.SearchResultPeopleView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:gravity="center_vertical"
-    android:layout_height="wrap_content"
-    android:padding="8dp"
-    android:orientation="horizontal">
-
-    <View
-        android:id="@+id/icon"
-        android:layout_marginRight="8dp"
-        android:layout_width="@dimen/deep_shortcut_icon_size"
-        android:layout_height="@dimen/deep_shortcut_icon_size" />
-
-    <TextView
-        android:layout_width="0dp"
-        android:textColor="?android:attr/textColorPrimary"
-        android:id="@+id/title"
-        android:textSize="@dimen/search_hero_title_size"
-        android:layout_height="wrap_content"
-        android:layout_weight="1" />
-
-    <ImageButton
-        android:id="@+id/provider_0"
-        android:scaleType="fitCenter"
-        android:adjustViewBounds="true"
-        android:layout_margin="5dp"
-        android:background="?android:attr/selectableItemBackground"
-        android:layout_width="@dimen/deep_shortcut_icon_size"
-        android:layout_height="@dimen/deep_shortcut_icon_size" />
-
-    <ImageButton
-        android:id="@+id/provider_1"
-        android:layout_margin="5dp"
-        android:scaleType="fitCenter"
-        android:adjustViewBounds="true"
-        android:background="?android:attr/selectableItemBackground"
-        android:layout_width="@dimen/deep_shortcut_icon_size"
-        android:layout_height="@dimen/deep_shortcut_icon_size" />
-
-    <ImageButton
-        android:id="@+id/provider_2"
-        android:layout_margin="5dp"
-        android:scaleType="fitCenter"
-        android:adjustViewBounds="true"
-        android:background="?android:attr/selectableItemBackground"
-        android:layout_width="@dimen/deep_shortcut_icon_size"
-        android:layout_height="@dimen/deep_shortcut_icon_size" />
-
-</com.android.launcher3.search.SearchResultPeopleView>
\ No newline at end of file
diff --git a/quickstep/res/layout/search_result_suggest.xml b/quickstep/res/layout/search_result_suggest.xml
deleted file mode 100644
index eb5313c..0000000
--- a/quickstep/res/layout/search_result_suggest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- 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.
--->
-<com.android.launcher3.search.SearchResultSuggestion xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    style="@style/BaseIcon"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:gravity="start|center_vertical"
-    android:textAlignment="viewStart"
-    android:textColor="?android:attr/textColorPrimary"
-    android:textSize="18sp"
-    android:padding="@dimen/dynamic_grid_edge_margin"
-    launcher:iconDisplay="hero_app"
-    android:drawableTint="?android:attr/textColorPrimary"
-    launcher:customIcon="@drawable/ic_allapps_search"
-    launcher:iconSizeOverride="24dp"
-    launcher:matchTextInsetWithQuery="true"
-    launcher:layoutHorizontal="true"
-    android:drawablePadding="@dimen/dynamic_grid_icon_drawable_padding">
-
-</com.android.launcher3.search.SearchResultSuggestion>
\ No newline at end of file
diff --git a/quickstep/res/layout/search_result_thumbnail.xml b/quickstep/res/layout/search_result_thumbnail.xml
index 0f25336..5062b76 100644
--- a/quickstep/res/layout/search_result_thumbnail.xml
+++ b/quickstep/res/layout/search_result_thumbnail.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.search.ThumbnailSearchResultView
+<com.android.launcher3.search.SearchResultThumbnailView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="125dp"
     android:layout_height="125dp"/>
\ No newline at end of file
diff --git a/quickstep/res/layout/search_result_widget_live.xml b/quickstep/res/layout/search_result_widget_live.xml
index ffbad55..f2ac6cd 100644
--- a/quickstep/res/layout/search_result_widget_live.xml
+++ b/quickstep/res/layout/search_result_widget_live.xml
@@ -1,5 +1,43 @@
 <?xml version="1.0" encoding="utf-8"?>
-<com.android.launcher3.search.SearchResultWidget android:layout_height="wrap_content"
+<com.android.launcher3.search.SearchResultWidget
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:paddingVertical="@dimen/widget_section_vertical_padding"
+    android:layout_marginBottom="@dimen/widget_section_vertical_padding"
     android:gravity="center"
-    android:layout_width="match_parent" />
\ No newline at end of file
+    >
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:orientation="horizontal"
+        android:layout_height="wrap_content">
+
+        <com.android.launcher3.BubbleTextView
+            android:id="@+id/widget_provider"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/widget_section_height"
+            android:drawablePadding="@dimen/widget_section_horizontal_padding"
+            android:focusable="true"
+            android:gravity="start|center_vertical"
+            android:paddingHorizontal="@dimen/widget_section_horizontal_padding"
+            android:paddingVertical="@dimen/widget_section_horizontal_padding"
+            android:singleLine="true"
+            android:textColor="?android:attr/textColorPrimary"
+            android:textSize="16sp"
+            android:textAlignment="viewStart"
+            launcher:iconDisplay="widget_section"
+            launcher:layoutHorizontal="true"
+            launcher:iconSizeOverride="@dimen/widget_section_icon_size" />
+
+        <TextView
+            android:id="@+id/widget_label"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/widget_section_height"
+            android:textSize="16sp" />
+
+    </LinearLayout>
+
+</com.android.launcher3.search.SearchResultWidget>
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 2518f42..09a3cfd 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -45,6 +45,7 @@
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.taskbar.TaskbarContainerView;
 import com.android.launcher3.taskbar.TaskbarController;
+import com.android.launcher3.taskbar.TaskbarStateHandler;
 import com.android.launcher3.uioverrides.RecentsViewStateController;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.UiThreadHelper;
@@ -82,6 +83,7 @@
     private OverviewActionsView mActionsView;
 
     private @Nullable TaskbarController mTaskbarController;
+    private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this);
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -245,13 +247,23 @@
                 getWorkspace(),
                 getDepthController(),
                 new RecentsViewStateController(this),
-                new BackButtonAlphaHandler(this)};
+                new BackButtonAlphaHandler(this),
+                getTaskbarStateHandler(),
+        };
     }
 
     public DepthController getDepthController() {
         return mDepthController;
     }
 
+    public @Nullable TaskbarController getTaskbarController() {
+        return mTaskbarController;
+    }
+
+    public TaskbarStateHandler getTaskbarStateHandler() {
+        return mTaskbarStateHandler;
+    }
+
     @Override
     public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) {
         QuickstepAppTransitionManagerImpl appTransitionManager =
@@ -296,6 +308,12 @@
             mDepthController.setActivityStarted(isStarted());
         }
 
+        if ((changeBits & ACTIVITY_STATE_RESUMED) != 0) {
+            if (mTaskbarController != null) {
+                mTaskbarController.onLauncherResumedOrPaused(hasBeenResumed());
+            }
+        }
+
         super.onActivityFlagsChanged(changeBits);
     }
 
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index fe5ce04..e6888d5 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -139,7 +139,7 @@
     private static final int LAUNCHER_RESUME_START_DELAY = 100;
     private static final int CLOSING_TRANSITION_DURATION_MS = 250;
 
-    protected static final int CONTENT_ALPHA_DURATION = 217;
+    public static final int CONTENT_ALPHA_DURATION = 217;
     protected static final int CONTENT_TRANSLATION_DURATION = 350;
 
     // Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down.
diff --git a/quickstep/src/com/android/launcher3/search/DeviceSearchAdapterProvider.java b/quickstep/src/com/android/launcher3/search/DeviceSearchAdapterProvider.java
index 834a624..acf6c15 100644
--- a/quickstep/src/com/android/launcher3/search/DeviceSearchAdapterProvider.java
+++ b/quickstep/src/com/android/launcher3/search/DeviceSearchAdapterProvider.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.allapps.AllAppsGridAdapter.VIEW_TYPE_ICON;
 
 import android.app.search.SearchTarget;
+import android.util.Log;
 import android.util.SparseIntArray;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -30,7 +31,6 @@
 import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsGridAdapter;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
-import com.android.launcher3.config.FeatureFlags;
 
 /**
  * Provides views for on-device search results
@@ -41,14 +41,13 @@
     public static final int VIEW_TYPE_SEARCH_SLICE = 1 << 7;
     public static final int VIEW_TYPE_SEARCH_ICON = (1 << 8) | VIEW_TYPE_ICON;
     public static final int VIEW_TYPE_SEARCH_ICON_ROW = (1 << 9);
-    public static final int VIEW_TYPE_SEARCH_PEOPLE = 1 << 11;
     public static final int VIEW_TYPE_SEARCH_THUMBNAIL = 1 << 12;
-    public static final int VIEW_TYPE_SEARCH_SUGGEST = 1 << 13;
     public static final int VIEW_TYPE_SEARCH_WIDGET_LIVE = 1 << 15;
     public static final int VIEW_TYPE_SEARCH_WIDGET_PREVIEW = 1 << 16;
 
-    private final AllAppsContainerView mAppsView;
+    private static final String TAG = "SearchServiceAdapterProvider";
 
+    private final AllAppsContainerView mAppsView;
     private final SparseIntArray mViewTypeToLayoutMap = new SparseIntArray();
 
     public DeviceSearchAdapterProvider(Launcher launcher, AllAppsContainerView appsView) {
@@ -59,9 +58,7 @@
         mViewTypeToLayoutMap.put(VIEW_TYPE_SEARCH_ICON, R.layout.search_result_icon);
         mViewTypeToLayoutMap.put(VIEW_TYPE_SEARCH_ICON_ROW, R.layout.search_result_icon_row);
         mViewTypeToLayoutMap.put(VIEW_TYPE_SEARCH_SLICE, R.layout.search_result_slice);
-        mViewTypeToLayoutMap.put(VIEW_TYPE_SEARCH_PEOPLE, R.layout.search_result_people_item);
         mViewTypeToLayoutMap.put(VIEW_TYPE_SEARCH_THUMBNAIL, R.layout.search_result_thumbnail);
-        mViewTypeToLayoutMap.put(VIEW_TYPE_SEARCH_SUGGEST, R.layout.search_result_suggest);
         mViewTypeToLayoutMap.put(VIEW_TYPE_SEARCH_WIDGET_LIVE, R.layout.search_result_widget_live);
         mViewTypeToLayoutMap.put(VIEW_TYPE_SEARCH_WIDGET_PREVIEW,
                 R.layout.search_result_widget_preview);
@@ -74,11 +71,7 @@
         SearchTargetHandler
                 payloadResultView =
                 (SearchTargetHandler) holder.itemView;
-        if (!FeatureFlags.USE_SEARCH_API.get()) {
-            payloadResultView.applySearchTarget(item.getSearchTargetLegacy());
-        } else {
-            payloadResultView.applySearchTarget(item.getSearchTarget(), item.getInlineItems());
-        }
+        payloadResultView.apply(item.getSearchTarget(), item.getInlineItems());
     }
 
     @Override
@@ -113,7 +106,8 @@
 
     /**
      * Determines what view type should be used to present search target.
-     * Returns -1 if viewType is not found
+     * Returns -1 if viewType is not found or if required field is not present
+     * to render the viewType.
      */
     public int getViewTypeForSearchTarget(SearchTarget t) {
         switch (t.getLayoutType()) {
@@ -122,14 +116,27 @@
             case LayoutType.ICON_SINGLE_VERTICAL_TEXT:
                 return VIEW_TYPE_SEARCH_ICON;
             case LayoutType.ICON_SLICE:
-                return VIEW_TYPE_SEARCH_SLICE;
-            case LayoutType.ICON_DOUBLE_HORIZONTAL_TEXT_BUTTON:
+                if (t.getSliceUri() != null) {
+                    return VIEW_TYPE_SEARCH_SLICE;
+                }
+                Log.w(TAG, "Dropping as LayoutType.ICON_SLICE target doesn't contain sliceUri.");
+                break;
             case LayoutType.ICON_DOUBLE_HORIZONTAL_TEXT:
             case LayoutType.ICON_SINGLE_HORIZONTAL_TEXT:
+            case LayoutType.ICON_DOUBLE_HORIZONTAL_TEXT_BUTTON:
                 return VIEW_TYPE_SEARCH_ICON_ROW;
-            default:
-                return -1;
-
+            case LayoutType.THUMBNAIL:
+                if (t.getSearchAction() != null) {
+                    return VIEW_TYPE_SEARCH_THUMBNAIL;
+                }
+                Log.w(TAG, "Dropping as LayoutType.THUMBNAIL target doesn't contain searchAction.");
+                break;
+            case LayoutType.WIDGET_PREVIEW:
+                return VIEW_TYPE_SEARCH_WIDGET_PREVIEW;
+            case LayoutType.WIDGET_LIVE:
+                return VIEW_TYPE_SEARCH_WIDGET_LIVE;
         }
+
+        return -1;
     }
 }
diff --git a/quickstep/src/com/android/launcher3/search/SearchAdapterItem.java b/quickstep/src/com/android/launcher3/search/SearchAdapterItem.java
index 01b1999..b402f61 100644
--- a/quickstep/src/com/android/launcher3/search/SearchAdapterItem.java
+++ b/quickstep/src/com/android/launcher3/search/SearchAdapterItem.java
@@ -18,9 +18,7 @@
 
 import static com.android.launcher3.search.DeviceSearchAdapterProvider.VIEW_TYPE_SEARCH_ICON;
 import static com.android.launcher3.search.DeviceSearchAdapterProvider.VIEW_TYPE_SEARCH_ICON_ROW;
-import static com.android.launcher3.search.DeviceSearchAdapterProvider.VIEW_TYPE_SEARCH_PEOPLE;
 import static com.android.launcher3.search.DeviceSearchAdapterProvider.VIEW_TYPE_SEARCH_SLICE;
-import static com.android.launcher3.search.DeviceSearchAdapterProvider.VIEW_TYPE_SEARCH_SUGGEST;
 import static com.android.launcher3.search.DeviceSearchAdapterProvider.VIEW_TYPE_SEARCH_THUMBNAIL;
 import static com.android.launcher3.search.DeviceSearchAdapterProvider.VIEW_TYPE_SEARCH_WIDGET_LIVE;
 import static com.android.launcher3.search.DeviceSearchAdapterProvider.VIEW_TYPE_SEARCH_WIDGET_PREVIEW;
@@ -43,17 +41,16 @@
 
 
     private static final int AVAILABLE_FOR_ACCESSIBILITY =
-            VIEW_TYPE_SEARCH_SLICE | VIEW_TYPE_SEARCH_PEOPLE | VIEW_TYPE_SEARCH_THUMBNAIL
-                    | VIEW_TYPE_SEARCH_ICON_ROW | VIEW_TYPE_SEARCH_ICON
-                    | VIEW_TYPE_SEARCH_WIDGET_PREVIEW | VIEW_TYPE_SEARCH_WIDGET_LIVE
-                    | VIEW_TYPE_SEARCH_SUGGEST;
+            VIEW_TYPE_SEARCH_SLICE | VIEW_TYPE_SEARCH_THUMBNAIL | VIEW_TYPE_SEARCH_ICON_ROW
+                    | VIEW_TYPE_SEARCH_ICON | VIEW_TYPE_SEARCH_WIDGET_PREVIEW
+                    | VIEW_TYPE_SEARCH_WIDGET_LIVE;
+
 
     public SearchAdapterItem(SearchTargetLegacy searchTargetLegacy, int type) {
         mSearchTargetLegacy = searchTargetLegacy;
         viewType = type;
     }
 
-
     public SearchAdapterItem(SearchTarget searchTarget, int type) {
         mSearchTarget = searchTarget;
         viewType = type;
diff --git a/quickstep/src/com/android/launcher3/search/SearchResultIcon.java b/quickstep/src/com/android/launcher3/search/SearchResultIcon.java
index 0b8d3cb..c353d7a 100644
--- a/quickstep/src/com/android/launcher3/search/SearchResultIcon.java
+++ b/quickstep/src/com/android/launcher3/search/SearchResultIcon.java
@@ -15,17 +15,26 @@
  */
 package com.android.launcher3.search;
 
+import static com.android.launcher3.model.data.SearchActionItemInfo.FLAG_BADGE_WITH_PACKAGE;
+import static com.android.launcher3.model.data.SearchActionItemInfo.FLAG_PRIMARY_ICON_FROM_TITLE;
+import static com.android.launcher3.search.SearchTargetUtil.BUNDLE_EXTRA_PRIMARY_ICON_FROM_TITLE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
 import android.app.search.SearchAction;
 import android.app.search.SearchTarget;
+import android.app.search.SearchTargetEvent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ShortcutInfo;
-import android.graphics.drawable.Drawable;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.Icon;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.AttributeSet;
@@ -37,15 +46,22 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.allapps.AllAppsStore;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.BitmapRenderer;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.model.data.SearchActionItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Themes;
 
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
 import java.util.List;
 import java.util.function.Consumer;
 
@@ -56,13 +72,17 @@
         SearchTargetHandler, View.OnClickListener,
         View.OnLongClickListener {
 
-    private static final String BUNDLE_EXTRA_SHOULD_START = "should_start";
-    private static final String BUNDLE_EXTRA_SHOULD_START_FOR_RESULT = "should_start_for_result";
+    //Play store thumbnail process workaround
+    private final Rect mTempRect = new Rect();
+    private final Paint mIconPaint = new Paint();
+    private static final int BITMAP_CROP_MASK_COLOR = 0xff424242;
 
     private final Launcher mLauncher;
 
+    private String mTargetId;
     private Consumer<ItemInfoWithIcon> mOnItemInfoChanged;
 
+
     public SearchResultIcon(Context context) {
         this(context, null, 0);
     }
@@ -93,73 +113,134 @@
      * Applies {@link SearchTarget} to view. registers a consumer after a corresponding
      * {@link ItemInfoWithIcon} is created
      */
-    public void applySearchTarget(SearchTarget searchTarget, List<SearchTarget> inlineItems,
+    public void apply(SearchTarget searchTarget, List<SearchTarget> inlineItems,
             Consumer<ItemInfoWithIcon> cb) {
         mOnItemInfoChanged = cb;
-        applySearchTarget(searchTarget, inlineItems);
+        apply(searchTarget, inlineItems);
     }
 
     @Override
-    public void applySearchTarget(SearchTarget parentTarget, List<SearchTarget> children) {
-        switch (parentTarget.getResultType()) {
-            case ResultType.APPLICATION:
-                prepareUsingApp(new ComponentName(parentTarget.getPackageName(),
-                        parentTarget.getExtras().getString("class")), parentTarget.getUserHandle());
-                mLongPressSupported = true;
-                break;
-            case ResultType.SHORTCUT:
-                prepareUsingShortcutInfo(parentTarget.getShortcutInfo());
-                mLongPressSupported = true;
-                break;
-            default:
-                prepareUsingSearchAction(parentTarget);
-                mLongPressSupported = false;
-                break;
+    public void apply(SearchTarget parentTarget, List<SearchTarget> children) {
+        mTargetId = parentTarget.getId();
+        if (parentTarget.getShortcutInfo() != null) {
+            prepareUsingShortcutInfo(parentTarget.getShortcutInfo());
+            mLongPressSupported = true;
+        } else if (parentTarget.getSearchAction() != null) {
+            prepareUsingSearchAction(parentTarget);
+            mLongPressSupported = false;
+        } else {
+            String className = parentTarget.getExtras().getString(SearchTargetUtil.EXTRA_CLASS);
+            prepareUsingApp(new ComponentName(parentTarget.getPackageName(), className),
+                    parentTarget.getUserHandle());
+            mLongPressSupported = true;
         }
     }
 
     private void prepareUsingSearchAction(SearchTarget searchTarget) {
         SearchAction searchAction = searchTarget.getSearchAction();
         Bundle extras = searchAction.getExtras();
+
         SearchActionItemInfo itemInfo = new SearchActionItemInfo(searchAction.getIcon(),
                 searchTarget.getPackageName(), searchTarget.getUserHandle(),
-                searchAction.getTitle());
+                searchAction.getTitle()
+        );
         itemInfo.setIntent(searchAction.getIntent());
         itemInfo.setPendingIntent(searchAction.getPendingIntent());
 
         //TODO: remove this after flags are introduced in SearchAction. Settings results require
         // startActivityForResult
         boolean isSettingsResult = searchTarget.getResultType() == ResultType.SETTING;
-        if ((extras != null && extras.getBoolean(BUNDLE_EXTRA_SHOULD_START_FOR_RESULT))
+        if ((extras != null && extras.getBoolean(
+                SearchTargetUtil.BUNDLE_EXTRA_SHOULD_START_FOR_RESULT))
                 || isSettingsResult) {
             itemInfo.setFlags(SearchActionItemInfo.FLAG_SHOULD_START_FOR_RESULT);
-        } else if (extras != null && extras.getBoolean(BUNDLE_EXTRA_SHOULD_START)) {
+        } else if (extras != null && extras.getBoolean(
+                SearchTargetUtil.BUNDLE_EXTRA_SHOULD_START)) {
             itemInfo.setFlags(SearchActionItemInfo.FLAG_SHOULD_START);
         }
-
+        if (extras != null && extras.getBoolean(
+                SearchTargetUtil.BUNDLE_EXTRA_BADGE_WITH_PACKAGE)) {
+            itemInfo.setFlags(FLAG_BADGE_WITH_PACKAGE);
+        }
+        if (extras != null && extras.getBoolean(BUNDLE_EXTRA_PRIMARY_ICON_FROM_TITLE)) {
+            itemInfo.setFlags(FLAG_PRIMARY_ICON_FROM_TITLE);
+        }
 
         notifyItemInfoChanged(itemInfo);
         LauncherAppState appState = LauncherAppState.getInstance(mLauncher);
         MODEL_EXECUTOR.post(() -> {
             try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
                 Icon icon = searchTarget.getSearchAction().getIcon();
-                Drawable d;
-                if (icon == null) {
-                    PackageItemInfo pkgInfo = new PackageItemInfo(searchTarget.getPackageName());
-                    pkgInfo.user = searchTarget.getUserHandle();
-                    appState.getIconCache().getTitleAndIconForApp(pkgInfo, false);
-                    itemInfo.bitmap = pkgInfo.bitmap;
+                BitmapInfo pkgBitmap = getPackageBitmap(appState, searchTarget);
+                if (itemInfo.hasFlags(FLAG_PRIMARY_ICON_FROM_TITLE)) {
+                    // create a bitmap with first char if FLAG_PRIMARY_ICON_FROM_TITLE is set
+                    itemInfo.bitmap = li.createIconBitmap(String.valueOf(itemInfo.title.charAt(0)),
+                            pkgBitmap.color);
+                } else if (icon == null) {
+                    // Use default icon from package name
+                    itemInfo.bitmap = pkgBitmap;
                 } else {
-                    d = itemInfo.getIcon().loadDrawable(getContext());
-                    itemInfo.bitmap = li.createBadgedIconBitmap(d, itemInfo.user,
-                            Build.VERSION.SDK_INT);
+                    boolean isPlayResult = searchTarget.getResultType() == ResultType.PLAY;
+                    if (isPlayResult) {
+                        Bitmap b = getPlayResultBitmap(searchAction.getIcon());
+                        itemInfo.bitmap = b == null
+                                ? BitmapInfo.LOW_RES_INFO : BitmapInfo.fromBitmap(b);
+                    } else {
+                        itemInfo.bitmap = li.createBadgedIconBitmap(icon.loadDrawable(getContext()),
+                                itemInfo.user, false);
+                    }
                 }
 
+                // badge with package name
+                if (itemInfo.hasFlags(FLAG_BADGE_WITH_PACKAGE) && itemInfo.bitmap != pkgBitmap) {
+                    itemInfo.bitmap = li.badgeBitmap(itemInfo.bitmap.icon, pkgBitmap);
+                }
             }
             MAIN_EXECUTOR.post(() -> applyFromSearchActionItemInfo(itemInfo));
         });
     }
 
+    private static BitmapInfo getPackageBitmap(LauncherAppState appState, SearchTarget target) {
+        PackageItemInfo pkgInfo = new PackageItemInfo(target.getPackageName());
+        pkgInfo.user = target.getUserHandle();
+        appState.getIconCache().getTitleAndIconForApp(pkgInfo, false);
+        return pkgInfo.bitmap;
+    }
+
+    private Bitmap getPlayResultBitmap(Icon icon) {
+        try {
+            int iconSize = getIconSize();
+            URL url = new URL(icon.getUri().toString());
+            URLConnection con = url.openConnection();
+            con.addRequestProperty("Cache-Control", "max-age: 0");
+            con.setUseCaches(true);
+            Bitmap bitmap = BitmapFactory.decodeStream(con.getInputStream());
+            return getRoundedBitmap(Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, false));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private Bitmap getRoundedBitmap(Bitmap bitmap) {
+        final int iconSize = bitmap.getWidth();
+        final float radius = Themes.getDialogCornerRadius(getContext());
+
+        return 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);
+        });
+    }
+
     private void prepareUsingApp(ComponentName componentName, UserHandle userHandle) {
         AllAppsStore appsStore = mLauncher.getAppsView().getAppsStore();
         AppInfo appInfo = appsStore.getApp(new ComponentKey(componentName, userHandle));
@@ -185,26 +266,27 @@
 
     @Override
     public boolean quickSelect() {
-        //TODO: event reporting
         this.performClick();
+        notifyEvent(mLauncher, mTargetId, SearchTargetEvent.ACTION_LAUNCH_KEYBOARD_FOCUS);
         return true;
     }
 
     @Override
     public void onClick(View view) {
-        //TODO: event reporting
-        mLauncher.getItemOnClickListener().onClick(this);
+        ItemClickHandler.INSTANCE.onClick(view);
+        notifyEvent(mLauncher, mTargetId, SearchTargetEvent.ACTION_LAUNCH_TOUCH);
     }
 
     @Override
     public boolean onLongClick(View view) {
-        //TODO: event reporting
         if (!mLongPressSupported) {
             return false;
         }
+        notifyEvent(mLauncher, mTargetId, SearchTargetEvent.ACTION_LONGPRESS);
         return ItemLongClickListener.INSTANCE_ALL_APPS.onLongClick(this);
     }
 
+
     private void notifyItemInfoChanged(ItemInfoWithIcon itemInfoWithIcon) {
         if (mOnItemInfoChanged != null) {
             mOnItemInfoChanged.accept(itemInfoWithIcon);
diff --git a/quickstep/src/com/android/launcher3/search/SearchResultIconRow.java b/quickstep/src/com/android/launcher3/search/SearchResultIconRow.java
index 4fb668e..7c3ed69 100644
--- a/quickstep/src/com/android/launcher3/search/SearchResultIconRow.java
+++ b/quickstep/src/com/android/launcher3/search/SearchResultIconRow.java
@@ -43,15 +43,15 @@
  */
 public class SearchResultIconRow extends LinearLayout implements SearchTargetHandler {
 
-    public static final int MAX_INLINE_ITEMS = 2;
+    public static final int MAX_INLINE_ITEMS = 3;
 
     protected final Launcher mLauncher;
     private final LauncherAppState mLauncherAppState;
-    private SearchResultIcon mResultIcon;
+    protected SearchResultIcon mResultIcon;
 
     private TextView mTitleView;
     private TextView mSubTitleView;
-    private final SearchResultIcon[] mInlineIcons = new SearchResultIcon[MAX_INLINE_ITEMS];
+    protected final SearchResultIcon[] mInlineIcons = new SearchResultIcon[MAX_INLINE_ITEMS];
 
     private PackageItemInfo mProviderInfo;
 
@@ -90,6 +90,7 @@
 
         mInlineIcons[0] = findViewById(R.id.shortcut_0);
         mInlineIcons[1] = findViewById(R.id.shortcut_1);
+        mInlineIcons[2] = findViewById(R.id.shortcut_2);
         for (SearchResultIcon inlineIcon : mInlineIcons) {
             inlineIcon.getLayoutParams().width = getIconSize();
         }
@@ -99,8 +100,9 @@
     }
 
     @Override
-    public void applySearchTarget(SearchTarget parentTarget, List<SearchTarget> children) {
-        mResultIcon.applySearchTarget(parentTarget, children, this::onItemInfoCreated);
+    public void apply(SearchTarget parentTarget, List<SearchTarget> children) {
+        showSubtitleIfNeeded(null);
+        mResultIcon.apply(parentTarget, children, this::onItemInfoCreated);
         if (parentTarget.getShortcutInfo() != null) {
             updateWithShortcutInfo(parentTarget.getShortcutInfo());
         } else if (parentTarget.getSearchAction() != null) {
@@ -127,7 +129,6 @@
         });
     }
 
-
     protected void showSubtitleIfNeeded(CharSequence subTitle) {
         if (!TextUtils.isEmpty(subTitle)) {
             mSubTitleView.setText(subTitle);
@@ -137,11 +138,10 @@
         }
     }
 
-
     protected void showInlineItems(List<SearchTarget> children) {
         for (int i = 0; i < MAX_INLINE_ITEMS; i++) {
             if (i < children.size()) {
-                mInlineIcons[i].applySearchTarget(children.get(0), new ArrayList<>());
+                mInlineIcons[i].apply(children.get(i), new ArrayList<>());
                 mInlineIcons[i].setVisibility(VISIBLE);
             } else {
                 mInlineIcons[i].setVisibility(GONE);
diff --git a/quickstep/src/com/android/launcher3/search/SearchResultIconSlice.java b/quickstep/src/com/android/launcher3/search/SearchResultIconSlice.java
index e6c952f..0ea2f8b 100644
--- a/quickstep/src/com/android/launcher3/search/SearchResultIconSlice.java
+++ b/quickstep/src/com/android/launcher3/search/SearchResultIconSlice.java
@@ -18,8 +18,8 @@
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
 import android.app.search.SearchTarget;
+import android.app.search.SearchTargetEvent;
 import android.content.Context;
-import android.net.Uri;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.widget.LinearLayout;
@@ -36,7 +36,6 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.systemui.plugins.shared.SearchTargetLegacy;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -44,17 +43,17 @@
 /**
  * A slice view wrapper with settings app icon at start
  */
-public class SearchResultIconSlice extends LinearLayout implements
-        SearchTargetHandler, SliceView.OnSliceActionListener {
+public class SearchResultIconSlice extends LinearLayout implements SearchTargetHandler,
+        SliceView.OnSliceActionListener {
 
     private static final String TAG = "SearchSliceController";
-    private static final String URI_EXTRA_KEY = "slice_uri";
+
+    private final Launcher mLauncher;
 
     private SliceView mSliceView;
     private SearchResultIcon mIcon;
     private LiveData<Slice> mSliceLiveData;
-    private SearchTargetLegacy mSearchTarget;
-    private final Launcher mLauncher;
+    private String mTargetId;
 
     public SearchResultIconSlice(Context context) {
         this(context, null, 0);
@@ -83,7 +82,8 @@
     }
 
     @Override
-    public void applySearchTarget(SearchTarget parentTarget, List<SearchTarget> children) {
+    public void apply(SearchTarget parentTarget, List<SearchTarget> children) {
+        mTargetId = parentTarget.getId();
         reset();
         updateIcon(parentTarget, children);
         try {
@@ -97,7 +97,7 @@
 
     private void updateIcon(SearchTarget parentTarget, List<SearchTarget> children) {
         if (children.size() == 1) {
-            mIcon.applySearchTarget(children.get(0), new ArrayList<>());
+            mIcon.apply(children.get(0), new ArrayList<>());
         } else {
             LauncherAppState appState = LauncherAppState.getInstance(getContext());
             MODEL_EXECUTOR.post(() -> {
@@ -121,7 +121,6 @@
         reset();
     }
 
-
     private void reset() {
         mSliceView.setOnSliceActionListener(null);
         if (mSliceLiveData != null) {
@@ -131,11 +130,6 @@
 
     @Override
     public void onSliceAction(@NonNull EventInfo eventInfo, @NonNull SliceItem sliceItem) {
-        //TODO: event reporting
+        notifyEvent(mLauncher, mTargetId, SearchTargetEvent.ACTION_TAP);
     }
-
-    private Uri getSliceUri() {
-        return mSearchTarget.getExtras().getParcelable(URI_EXTRA_KEY);
-    }
-
 }
diff --git a/quickstep/src/com/android/launcher3/search/SearchResultPeopleView.java b/quickstep/src/com/android/launcher3/search/SearchResultPeopleView.java
deleted file mode 100644
index f3355da..0000000
--- a/quickstep/src/com/android/launcher3/search/SearchResultPeopleView.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.search;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Process;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
-import androidx.core.graphics.drawable.RoundedBitmapDrawable;
-import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.LauncherIcons;
-import com.android.systemui.plugins.shared.SearchTargetLegacy;
-
-import java.util.ArrayList;
-
-/**
- * A view representing a single people search result in all apps
- */
-public class SearchResultPeopleView extends LinearLayout implements
-        SearchTargetHandler {
-
-    public static final String TARGET_TYPE_PEOPLE = "people";
-
-    private final int mIconSize;
-    private final int mButtonSize;
-    private final PackageManager mPackageManager;
-    private View mIconView;
-    private TextView mTitleView;
-    private ImageButton[] mProviderButtons = new ImageButton[3];
-    private Intent mIntent;
-
-
-    private SearchTargetLegacy mSearchTarget;
-
-    public SearchResultPeopleView(Context context) {
-        this(context, null, 0);
-    }
-
-    public SearchResultPeopleView(Context context,
-            @Nullable AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SearchResultPeopleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        DeviceProfile deviceProfile = Launcher.getLauncher(getContext()).getDeviceProfile();
-        mPackageManager = getContext().getPackageManager();
-        mIconSize = deviceProfile.iconSizePx;
-        mButtonSize = (int) (deviceProfile.iconSizePx / 1.5f);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mIconView = findViewById(R.id.icon);
-        mIconView.getLayoutParams().height = mIconSize;
-        mIconView.getLayoutParams().width = mIconSize;
-        mTitleView = findViewById(R.id.title);
-        mProviderButtons[0] = findViewById(R.id.provider_0);
-        mProviderButtons[1] = findViewById(R.id.provider_1);
-        mProviderButtons[2] = findViewById(R.id.provider_2);
-        for (ImageButton button : mProviderButtons) {
-            button.getLayoutParams().width = mButtonSize;
-            button.getLayoutParams().height = mButtonSize;
-        }
-    }
-
-    @Override
-    public void applySearchTarget(SearchTargetLegacy searchTarget) {
-        mSearchTarget = searchTarget;
-        Bundle payload = searchTarget.getExtras();
-        mTitleView.setText(payload.getString("title"));
-        mIntent = payload.getParcelable("intent");
-        Bitmap contactIcon = payload.getParcelable("icon");
-        try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
-            BitmapInfo badgeInfo = li.createBadgedIconBitmap(
-                    getAppIcon(mIntent.getPackage()), Process.myUserHandle(),
-                    Build.VERSION.SDK_INT);
-            setIcon(li.badgeBitmap(roundBitmap(contactIcon), badgeInfo).icon, false);
-        } catch (Exception e) {
-            setIcon(contactIcon, true);
-        }
-
-        ArrayList<Bundle> providers = payload.getParcelableArrayList("providers");
-        for (int i = 0; i < mProviderButtons.length; i++) {
-            ImageButton button = mProviderButtons[i];
-            if (providers != null && i < providers.size()) {
-                Bundle provider = providers.get(i);
-                Intent intent = provider.getParcelable("intent");
-                setupProviderButton(button, provider, intent);
-                UI_HELPER_EXECUTOR.post(() -> {
-                    String pkg = provider.getString("package_name");
-                    Drawable appIcon = getAppIcon(pkg);
-                    if (appIcon != null) {
-                        MAIN_EXECUTOR.post(() -> button.setImageDrawable(appIcon));
-                    }
-                });
-                button.setVisibility(VISIBLE);
-            } else {
-                button.setVisibility(GONE);
-            }
-        }
-    }
-
-    /**
-     * 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);
-        d.setCornerRadius(R.attr.folderIconRadius);
-        d.setBounds(0, 0, mIconSize, mIconSize);
-        final Bitmap bitmap = Bitmap.createBitmap(d.getBounds().width(), d.getBounds().height(),
-                Bitmap.Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
-        d.draw(canvas);
-        return bitmap;
-    }
-
-    private void setIcon(Bitmap icon, Boolean round) {
-        if (round) {
-            RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon);
-            d.setCornerRadius(R.attr.folderIconRadius);
-            d.setBounds(0, 0, mIconSize, mIconSize);
-            mIconView.setBackground(d);
-        } else {
-            mIconView.setBackground(new BitmapDrawable(getResources(), icon));
-        }
-    }
-
-
-    private Drawable getAppIcon(String pkg) {
-        try {
-            ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
-                    pkg, 0);
-            return applicationInfo.loadIcon(mPackageManager);
-        } catch (PackageManager.NameNotFoundException ignored) {
-            return null;
-        }
-    }
-
-    private void setupProviderButton(ImageButton button, Bundle provider, Intent intent) {
-        Launcher launcher = Launcher.getLauncher(getContext());
-        button.setOnClickListener(b -> {
-            launcher.startActivitySafely(b, intent, null);
-            Bundle bundle = new Bundle();
-            bundle.putBundle("provider", provider);
-        });
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/search/SearchResultSuggestion.java b/quickstep/src/com/android/launcher3/search/SearchResultSuggestion.java
deleted file mode 100644
index 6a6bd1b..0000000
--- a/quickstep/src/com/android/launcher3/search/SearchResultSuggestion.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.search;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.ViewGroup;
-
-import com.android.launcher3.R;
-import com.android.launcher3.views.BaseDragLayer;
-
-/**
- * {@link SearchResultIconRow} with custom drawable resource
- */
-public class SearchResultSuggestion extends SearchResultIcon {
-
-    public static final String TARGET_TYPE_SUGGEST = "suggest";
-    private final Drawable mCustomIcon;
-
-    public SearchResultSuggestion(Context context) {
-        this(context, null, 0);
-    }
-
-    public SearchResultSuggestion(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SearchResultSuggestion(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.SearchResultSuggestion, defStyle, 0);
-        mCustomIcon = a.getDrawable(R.styleable.SearchResultSuggestion_customIcon);
-        a.recycle();
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        ViewGroup.LayoutParams lp = getLayoutParams();
-        lp.height = BaseDragLayer.LayoutParams.WRAP_CONTENT;
-    }
-
-    @Override
-    protected void setIcon(Drawable icon) {
-        super.setIcon(mCustomIcon);
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/search/SearchResultThumbnailView.java b/quickstep/src/com/android/launcher3/search/SearchResultThumbnailView.java
new file mode 100644
index 0000000..8803c98
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/search/SearchResultThumbnailView.java
@@ -0,0 +1,102 @@
+/*
+ * 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.search;
+
+
+import android.app.search.SearchTarget;
+import android.app.search.SearchTargetEvent;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.model.data.SearchActionItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.util.Themes;
+
+import java.util.List;
+
+/**
+ * A view representing a high confidence app search result that includes shortcuts
+ */
+public class SearchResultThumbnailView extends androidx.appcompat.widget.AppCompatImageView
+        implements SearchTargetHandler, View.OnClickListener {
+
+    private SearchTarget mSearchTarget;
+
+    public SearchResultThumbnailView(Context context) {
+        super(context);
+    }
+
+    public SearchResultThumbnailView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public SearchResultThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        setOnFocusChangeListener(Launcher.getLauncher(getContext()).getFocusHandler());
+        setOnClickListener(this);
+    }
+
+    @Override
+    public void apply(SearchTarget parentTarget, List<SearchTarget> children) {
+        mSearchTarget = parentTarget;
+        Bitmap bitmap;
+
+        SearchActionItemInfo itemInfo = new SearchActionItemInfo(
+                parentTarget.getSearchAction().getIcon(),
+                parentTarget.getPackageName(),
+                parentTarget.getUserHandle(),
+                parentTarget.getSearchAction().getTitle());
+        itemInfo.setIntent(parentTarget.getSearchAction().getIntent());
+        itemInfo.setPendingIntent(parentTarget.getSearchAction().getPendingIntent());
+
+        bitmap = ((BitmapDrawable) itemInfo.getIcon()
+                .loadDrawable(getContext())).getBitmap();
+        // crop
+        if (bitmap.getWidth() < bitmap.getHeight()) {
+            bitmap = Bitmap.createBitmap(bitmap, 0,
+                    bitmap.getHeight() / 2 - bitmap.getWidth() / 2,
+                    bitmap.getWidth(), bitmap.getWidth());
+        } else {
+            bitmap = Bitmap.createBitmap(bitmap, bitmap.getWidth() / 2 - bitmap.getHeight() / 2,
+                    0,
+                    bitmap.getHeight(), bitmap.getHeight());
+        }
+        setTag(itemInfo);
+
+        RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null, bitmap);
+        drawable.setCornerRadius(Themes.getDialogCornerRadius(getContext()));
+        setImageDrawable(drawable);
+    }
+
+    @Override
+    public void onClick(View view) {
+        ItemClickHandler.onClickSearchAction(Launcher.getLauncher(getContext()),
+                (SearchActionItemInfo) view.getTag());
+        notifyEvent(getContext(), mSearchTarget.getId(), SearchTargetEvent.ACTION_LAUNCH_TOUCH);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/search/SearchResultWidget.java b/quickstep/src/com/android/launcher3/search/SearchResultWidget.java
index c6bdb68..4c64265 100644
--- a/quickstep/src/com/android/launcher3/search/SearchResultWidget.java
+++ b/quickstep/src/com/android/launcher3/search/SearchResultWidget.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.search;
 
+import android.app.search.SearchTarget;
+import android.app.search.SearchTargetEvent;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
@@ -23,31 +25,34 @@
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CheckLongPressHelper;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
 import com.android.launcher3.allapps.search.SearchWidgetInfoContainer;
 import com.android.launcher3.dragndrop.DraggableView;
+import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
-import com.android.systemui.plugins.shared.SearchTargetLegacy;
+
+import java.util.List;
+
 
 /**
  * displays live version of a widget upon receiving {@link AppWidgetProviderInfo} from Search
  * provider
  */
-public class SearchResultWidget extends RelativeLayout implements
-        SearchTargetHandler, DraggableView, View.OnLongClickListener {
+public class SearchResultWidget extends LinearLayout implements SearchTargetHandler, DraggableView,
+        View.OnLongClickListener {
 
-    private static final String TAG = "SearchResultWidget";
-
-    public static final String TARGET_TYPE_WIDGET_LIVE = "widget";
 
     private final Rect mWidgetOffset = new Rect();
 
@@ -57,10 +62,9 @@
     private final AppWidgetHostView mHostView;
     private final float mScaleToFit;
 
-    private SearchTargetLegacy mSearchTarget;
-    private AppWidgetProviderInfo mProviderInfo;
-
     private SearchWidgetInfoContainer mInfoContainer;
+    private BubbleTextView mWidgetProvider;
+    private TextView mWidgetLabel;
 
     public SearchResultWidget(@NonNull Context context) {
         this(context, null, 0);
@@ -81,9 +85,8 @@
 
         // detect tap event on widget container for search target event reporting
         mClickDetector = new GestureDetector(context,
-                new ClickListener(() -> {
-                }));
-
+                new ClickListener(
+                        () -> reportEvent(SearchTargetEvent.ACTION_LAUNCH_TOUCH)));
         mLongPressHelper = new CheckLongPressHelper(this);
         mLongPressHelper.setLongPressTimeoutFactor(1);
         setOnLongClickListener(this);
@@ -92,26 +95,17 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        mWidgetProvider = findViewById(R.id.widget_provider);
+        mWidgetLabel = findViewById(R.id.widget_label);
         addView(mHostView);
     }
 
     @Override
-    public void applySearchTarget(SearchTargetLegacy searchTarget) {
-        if (searchTarget.getExtras() == null
-                || searchTarget.getExtras().getParcelable("provider") == null) {
-            setVisibility(GONE);
-            return;
-        }
-        AppWidgetProviderInfo providerInfo = searchTarget.getExtras().getParcelable("provider");
-        if (mProviderInfo != null && providerInfo.provider.equals(mProviderInfo.provider)
-                && providerInfo.getProfile().equals(mProviderInfo.getProfile())) {
-            return;
-        }
+    public void apply(SearchTarget parentTarget, List<SearchTarget> children) {
+        AppWidgetProviderInfo providerInfo = parentTarget.getAppWidgetProviderInfo();
         removeListener();
 
-        mSearchTarget = searchTarget;
-        mProviderInfo = providerInfo;
-
+        showWidgetInfo(providerInfo);
         mInfoContainer = mLauncher.getLiveSearchManager().getPlaceHolderWidget(providerInfo);
         if (mInfoContainer == null) {
             setVisibility(GONE);
@@ -129,6 +123,14 @@
         setTag(info);
     }
 
+    private void showWidgetInfo(AppWidgetProviderInfo providerInfo) {
+        String title = providerInfo.loadLabel(mLauncher.getPackageManager());
+        PackageItemInfo pinfo = new PackageItemInfo(providerInfo.provider.getPackageName());
+        pinfo.user = providerInfo.getProfile();
+        mWidgetProvider.applyFromItemInfoWithIcon(pinfo);
+        mWidgetLabel.setText(title);
+    }
+
     /**
      * Stops hostView from getting updates on a widget provider
      */
@@ -138,6 +140,11 @@
         }
     }
 
+    private void reportEvent(int eventType) {
+        SearchSessionTracker.INSTANCE.get(getContext()).notifyEvent(
+                new SearchTargetEvent.Builder("search target id", eventType).build());
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         mLongPressHelper.onTouchEvent(ev);
@@ -179,6 +186,7 @@
         return false;
     }
 
+
     static class ClickListener extends GestureDetector.SimpleOnGestureListener {
         private final Runnable mCb;
 
diff --git a/quickstep/src/com/android/launcher3/search/SearchResultWidgetPreview.java b/quickstep/src/com/android/launcher3/search/SearchResultWidgetPreview.java
index 22f0b76..5bf1908 100644
--- a/quickstep/src/com/android/launcher3/search/SearchResultWidgetPreview.java
+++ b/quickstep/src/com/android/launcher3/search/SearchResultWidgetPreview.java
@@ -18,6 +18,8 @@
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import android.app.search.SearchTarget;
+import android.app.search.SearchTargetEvent;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.graphics.Point;
@@ -39,24 +41,21 @@
 import com.android.launcher3.widget.PendingItemDragHelper;
 import com.android.launcher3.widget.WidgetCell;
 import com.android.launcher3.widget.WidgetImageView;
-import com.android.systemui.plugins.shared.SearchTargetLegacy;
+
+import java.util.List;
 
 /**
  * displays preview of a widget upon receiving {@link AppWidgetProviderInfo} from Search provider
  */
-public class SearchResultWidgetPreview extends LinearLayout implements
-        SearchTargetHandler, View.OnLongClickListener,
-        View.OnClickListener {
+public class SearchResultWidgetPreview extends LinearLayout implements SearchTargetHandler,
+        View.OnClickListener, View.OnLongClickListener {
 
-    public static final String TARGET_TYPE_WIDGET_PREVIEW = "widget_preview";
     private final Launcher mLauncher;
     private final LauncherAppState mAppState;
     private WidgetCell mWidgetCell;
     private Toast mWidgetToast;
 
-    private SearchTargetLegacy mSearchTarget;
-
-
+    private String mTargetId;
     public SearchResultWidgetPreview(Context context) {
         this(context, null, 0);
     }
@@ -82,14 +81,9 @@
     }
 
     @Override
-    public void applySearchTarget(SearchTargetLegacy searchTarget) {
-        if (searchTarget.getExtras() == null
-                || searchTarget.getExtras().getParcelable("provider") == null) {
-            setVisibility(GONE);
-            return;
-        }
-        mSearchTarget = searchTarget;
-        AppWidgetProviderInfo providerInfo = searchTarget.getExtras().getParcelable("provider");
+    public void apply(SearchTarget parentTarget, List<SearchTarget> children) {
+        mTargetId = parentTarget.getId();
+        AppWidgetProviderInfo providerInfo = parentTarget.getAppWidgetProviderInfo();
         LauncherAppWidgetProviderInfo pInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(
                 getContext(), providerInfo);
         MODEL_EXECUTOR.post(() -> {
@@ -100,7 +94,6 @@
                 mWidgetCell.ensurePreview();
             });
         });
-
     }
 
     @Override
@@ -120,11 +113,18 @@
         new PendingItemDragHelper(mWidgetCell).startDrag(
                 imageView.getBitmapBounds(), imageView.getBitmap().getWidth(), imageView.getWidth(),
                 new Point(loc[0], loc[1]), mLauncher.getAppsView(), new DragOptions());
+        reportEvent(SearchTargetEvent.ACTION_LONGPRESS);
         return true;
     }
 
     @Override
     public void onClick(View view) {
         mWidgetToast = BaseWidgetSheet.showWidgetToast(getContext(), mWidgetToast);
+        reportEvent(SearchTargetEvent.ACTION_LAUNCH_TOUCH);
+    }
+
+    private void reportEvent(int eventType) {
+        SearchSessionTracker.INSTANCE.get(getContext()).notifyEvent(
+                new SearchTargetEvent.Builder(mTargetId, eventType).build());
     }
 }
diff --git a/quickstep/src/com/android/launcher3/search/SearchSectionHeaderView.java b/quickstep/src/com/android/launcher3/search/SearchSectionHeaderView.java
index e015122..9276841 100644
--- a/quickstep/src/com/android/launcher3/search/SearchSectionHeaderView.java
+++ b/quickstep/src/com/android/launcher3/search/SearchSectionHeaderView.java
@@ -27,8 +27,7 @@
 /**
  * Header text view that shows a title for a given section in All apps search
  */
-public class SearchSectionHeaderView extends TextView implements
-        SearchTargetHandler {
+public class SearchSectionHeaderView extends TextView implements SearchTargetHandler {
 
     public SearchSectionHeaderView(Context context) {
         super(context);
@@ -44,7 +43,7 @@
     }
 
     @Override
-    public void applySearchTarget(SearchTarget parentTarget, List<SearchTarget> children) {
+    public void apply(SearchTarget parentTarget, List<SearchTarget> children) {
         setText(parentTarget.getSearchAction().getTitle());
         setVisibility(VISIBLE);
     }
diff --git a/quickstep/src/com/android/launcher3/search/SearchServicePipeline.java b/quickstep/src/com/android/launcher3/search/SearchServicePipeline.java
index 6585213..fac6ba7 100644
--- a/quickstep/src/com/android/launcher3/search/SearchServicePipeline.java
+++ b/quickstep/src/com/android/launcher3/search/SearchServicePipeline.java
@@ -27,6 +27,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.WorkerThread;
+
 import com.android.app.search.ResultType;
 import com.android.launcher3.allapps.AllAppsGridAdapter;
 import com.android.launcher3.allapps.AllAppsSectionDecorator;
@@ -46,10 +48,11 @@
     private static final int SUPPORTED_RESULT_TYPES =
             ResultType.APPLICATION | ResultType.SHORTCUT | ResultType.PLAY | ResultType.PEOPLE
                     | ResultType.SETTING;
+
+    private static final boolean DEBUG = true;
     private static final int REQUEST_TIMEOUT = 200;
     private static final String TAG = "SearchServicePipeline";
 
-
     private final Context mContext;
     private final SearchSession mSession;
     private final DeviceSearchAdapterProvider mAdapterProvider;
@@ -63,16 +66,22 @@
         SearchUiManager manager = context.getSystemService(SearchUiManager.class);
         mSession = manager.createSearchSession(
                 new SearchContext(SUPPORTED_RESULT_TYPES, REQUEST_TIMEOUT, null));
+        SearchSessionTracker.getInstance(context).setSearchSession(mSession);
     }
 
+    @WorkerThread
     @Override
     public void query(String input, Consumer<ArrayList<AllAppsGridAdapter.AdapterItem>> callback,
             CancellationSignal cancellationSignal) {
         mCanceled = false;
         Query query = new Query(input, System.currentTimeMillis(), null);
-        mSession.query(query, UI_HELPER_EXECUTOR, items -> {
+        mSession.query(query, UI_HELPER_EXECUTOR, targets -> {
             if (!mCanceled) {
-                callback.accept(this.onResult(items));
+                if (DEBUG) {
+                    printSearchTargets(input, targets);
+                }
+                SearchSessionTracker.getInstance(mContext).setQuery(query);
+                callback.accept(this.onResult(targets));
             }
             Log.w(TAG, "Ignoring results due to cancel signal");
         });
@@ -111,6 +120,13 @@
         return new ArrayList<>(adapterMap.values());
     }
 
+    private void printSearchTargets(String query, List<SearchTarget> results) {
+        Log.d(TAG, " query=" + query + " size=" + results.size());
+        for (SearchTarget s : results) {
+            Log.d(TAG, "layoutType=" + s.getLayoutType() + " resultType=" + s.getResultType());
+        }
+    }
+
     /**
      * Adds a child SearchTarget to a collection of searchTarget children with a shared parentId.
      * Returns false if no parent searchTarget with id=$parentId does not exists.
diff --git a/quickstep/src/com/android/launcher3/search/SearchSessionTracker.java b/quickstep/src/com/android/launcher3/search/SearchSessionTracker.java
new file mode 100644
index 0000000..3079965
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/search/SearchSessionTracker.java
@@ -0,0 +1,76 @@
+/*
+ * 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.search;
+
+import android.app.search.Query;
+import android.app.search.SearchSession;
+import android.app.search.SearchTarget;
+import android.app.search.SearchTargetEvent;
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.WorkerThread;
+
+import com.android.launcher3.util.MainThreadInitializedObject;
+
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+/**
+ * A singleton class to track and report search events back to SearchSession
+ */
+public class SearchSessionTracker {
+
+    private static final String TAG = "SearchSessionTracker";
+
+    @Nullable
+    private SearchSession mSession;
+    private Query mQuery;
+
+    public static final MainThreadInitializedObject<SearchSessionTracker> INSTANCE =
+            new MainThreadInitializedObject<>(SearchSessionTracker::new);
+
+    private SearchSessionTracker(Context context) {
+    }
+
+    /**
+     * Returns instance of SearchSessionTracker
+     */
+    public static SearchSessionTracker getInstance(Context context) {
+        return SearchSessionTracker.INSTANCE.get(context);
+    }
+
+    @WorkerThread
+    public void setSearchSession(SearchSession session) {
+        mSession = session;
+    }
+
+    @WorkerThread
+    public void setQuery(Query query) {
+        mQuery = query;
+    }
+
+    /**
+     * Send the user event handling back to the {@link SearchSession} object.
+     */
+    public void notifyEvent(SearchTargetEvent event) {
+        if (mSession == null) {
+            Log.d(TAG, "Dropping event " + event.getTargetId());
+        }
+        Log.d(TAG, "notifyEvent:" + mQuery.getInput() + ":" + event.getTargetId());
+        UI_HELPER_EXECUTOR.post(() -> mSession.notifyEvent(mQuery, event));
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/search/SearchTargetHandler.java b/quickstep/src/com/android/launcher3/search/SearchTargetHandler.java
index 67502f6..acf6f8a 100644
--- a/quickstep/src/com/android/launcher3/search/SearchTargetHandler.java
+++ b/quickstep/src/com/android/launcher3/search/SearchTargetHandler.java
@@ -17,8 +17,8 @@
 package com.android.launcher3.search;
 
 import android.app.search.SearchTarget;
-
-import com.android.systemui.plugins.shared.SearchTargetLegacy;
+import android.app.search.SearchTargetEvent;
+import android.content.Context;
 
 import java.util.List;
 
@@ -28,20 +28,9 @@
 public interface SearchTargetHandler {
 
     /**
-     * Update view using values from {@link SearchTargetLegacy}
-     *
-     * @deprecated Use {@link SearchTargetHandler#applySearchTarget(SearchTarget, List)} instead
+     * Update view using values from {@link SearchTarget}
      */
-    @Deprecated
-    default void applySearchTarget(SearchTargetLegacy searchTarget) {
-    }
-
-
-    /**
-     * Update view using values from {@link SearchTargetLegacy}
-     */
-    default void applySearchTarget(SearchTarget parentTarget, List<SearchTarget> children) {
-    }
+    default void apply(SearchTarget parentTarget, List<SearchTarget> children) { }
 
     /**
      * Handle IME quick select event. returns whether event was handled.
@@ -50,4 +39,8 @@
         return false;
     }
 
+    default void notifyEvent(Context context, String id, int eventType) {
+        SearchTargetEvent.Builder builder = new SearchTargetEvent.Builder(id, eventType);
+        SearchSessionTracker.getInstance(context).notifyEvent(builder.build());
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/search/SearchTargetUtil.java b/quickstep/src/com/android/launcher3/search/SearchTargetUtil.java
new file mode 100644
index 0000000..0abed03
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/search/SearchTargetUtil.java
@@ -0,0 +1,184 @@
+/*
+ * 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.search;
+
+import static com.android.app.search.LayoutType.ICON_DOUBLE_HORIZONTAL_TEXT;
+import static com.android.app.search.LayoutType.ICON_SINGLE_HORIZONTAL_TEXT;
+import static com.android.app.search.LayoutType.THUMBNAIL;
+import static com.android.app.search.ResultType.ACTION;
+import static com.android.app.search.ResultType.SCREENSHOT;
+import static com.android.app.search.ResultType.SUGGEST;
+
+import android.app.PendingIntent;
+import android.app.search.SearchAction;
+import android.app.search.SearchTarget;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+
+import com.android.app.search.ResultType;
+
+public class SearchTargetUtil {
+
+    public static final String BUNDLE_EXTRA_SHOULD_START = "should_start";
+    public static final String BUNDLE_EXTRA_SHOULD_START_FOR_RESULT = "should_start_for_result";
+    public static final String BUNDLE_EXTRA_BADGE_WITH_PACKAGE = "badge_with_package";
+    public static final String BUNDLE_EXTRA_PRIMARY_ICON_FROM_TITLE = "primary_icon_from_title";
+
+    public static final String EXTRA_CLASS = "class";
+
+    private static final String TITLE = " title: weather ";
+    private static final String SUBTITLE = " subtitle: 68 degrees ";
+    private static final String PACKAGE2 = "com.google.android.gm";
+    private static final UserHandle USERHANDLE = Process.myUserHandle();
+
+
+    /**
+     * Generate SearchTargetUtil for ICON_DOUBLE_HORIZONTAL_TEXT layout type.
+     *
+     * targets.add(SearchTargetUtil.generateIconDoubleHorizontalText_SearchAction(
+     * mContext, "red", Color.RED));
+     * targets.add(SearchTargetUtil.generateIconDoubleHorizontalText_SearchAction(
+     * mContext, "yellow", Color.YELLOW));
+     */
+    public static SearchTarget generateIconDoubleHorizontalText_SearchAction(
+            Context context, String id, int color) {
+        SearchTarget.Builder builder =
+                new SearchTarget.Builder(ACTION, ICON_DOUBLE_HORIZONTAL_TEXT, id)
+                        .setPackageName(PACKAGE2) /* required */
+                        .setUserHandle(USERHANDLE); /* required */
+
+        Intent intent = new Intent("com.google.android.googlequicksearchbox.GENERIC_QUERY");
+        intent.putExtra("query", "weather");
+        intent.putExtra("full_screen", false);
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(
+                        context, 1, intent,
+                        PendingIntent.FLAG_UPDATE_CURRENT);
+
+        Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        canvas.drawColor(color);
+        Icon icon = Icon.createWithAdaptiveBitmap(bitmap);
+
+        Bundle b = new Bundle();
+        b.putBoolean(BUNDLE_EXTRA_SHOULD_START_FOR_RESULT, true);
+        b.putBoolean(BUNDLE_EXTRA_BADGE_WITH_PACKAGE, true);
+        b.putBoolean(BUNDLE_EXTRA_PRIMARY_ICON_FROM_TITLE, true);
+
+        builder.setSearchAction(new SearchAction.Builder(id, id + TITLE)
+                .setSubtitle(id + SUBTITLE)
+                .setPendingIntent(pendingIntent)
+                .setIcon(icon)
+                .setExtras(b)
+                .build());
+        return builder.build();
+    }
+
+    /**
+     * Inside SearchServicePipeline, add following samples to test the search target.
+     *
+     * targets.add(SearchTargetUtil.generateThumbnail_SearchAction("blue", Color.BLUE));
+     * targets.add(SearchTargetUtil.generateThumbnail_SearchAction("red", Color.RED));
+     * targets.add(SearchTargetUtil.generateThumbnail_SearchAction("green", Color.GREEN));
+     */
+    public static SearchTarget generateThumbnail_SearchAction(String id, int color) {
+        SearchTarget.Builder builder =
+                new SearchTarget.Builder(SCREENSHOT, THUMBNAIL, id)
+                        .setPackageName(PACKAGE2) /* required */
+                        .setUserHandle(USERHANDLE); /* required */
+
+
+        Intent intent = new Intent(Intent.ACTION_VIEW)
+                .setData(Uri.parse("uri blah blah"))
+                .setType("image/*")
+                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        Bitmap bitmap = Bitmap.createBitmap(1000, 500, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        canvas.drawColor(color);
+        Icon icon = Icon.createWithBitmap(bitmap);
+
+        builder.setSearchAction(new SearchAction.Builder(id, TITLE)
+                .setSubtitle(SUBTITLE)
+                .setIcon(icon)
+                .setIntent(intent)
+                .build());
+        return builder.build();
+
+    }
+
+    /**
+     * targets.add(SearchTargetUtil.generateIconHorizontalText_SearchAction(
+     * mContext, "red", Color.RED));
+     * targets.add(SearchTargetUtil.generateIconHorizontalText_SearchAction(
+     * mContext, "yellow", Color.YELLOW));
+     */
+    public static SearchTarget generateIconHorizontalText_SearchAction(
+            Context context, String id, int color) {
+        String fallbackQuery = "How to make cookie";
+        SearchTarget.Builder builder =
+                new SearchTarget.Builder(SUGGEST, ICON_SINGLE_HORIZONTAL_TEXT, id)
+                        .setPackageName(PACKAGE2) /* required */
+                        .setUserHandle(USERHANDLE); /* required */
+
+        Intent intent3 = new Intent("com.google.android.googlequicksearchbox.GENERIC_QUERY");
+        intent3.putExtra("query", fallbackQuery);
+        intent3.putExtra("full_screen", false);
+        PendingIntent pendingIntent3 =
+                PendingIntent.getActivity(
+                        context, 1, intent3,
+                        PendingIntent.FLAG_UPDATE_CURRENT);
+
+        Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        canvas.drawColor(color);
+        Icon icon = Icon.createWithAdaptiveBitmap(bitmap);
+
+        Bundle extra = new Bundle();
+        extra.putBoolean(BUNDLE_EXTRA_SHOULD_START_FOR_RESULT, true);
+
+        SearchAction searchAction = new SearchAction.Builder(id, fallbackQuery)
+                .setPendingIntent(pendingIntent3)
+                .setIcon(icon)
+                .setExtras(extra)
+                .build();
+        return builder.setSearchAction(searchAction).build();
+    }
+
+
+    /**
+     * Generate SearchTargetUtil for ICON_DOUBLE_HORIZONTAL_TEXT layout type.
+     */
+    public static SearchTarget generateIconDoubleHorizontalText_ShortcutInfo(Context context) {
+        String id = "23456";
+        SearchTarget.Builder builder =
+                new SearchTarget.Builder(ResultType.SHORTCUT, ICON_DOUBLE_HORIZONTAL_TEXT, id)
+                        .setPackageName("com.google.android.gm") /* required */
+                        .setUserHandle(UserHandle.CURRENT); /* required */
+
+        builder.setShortcutInfo(new ShortcutInfo.Builder(context, id).build());
+        return builder.build();
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/search/ThumbnailSearchResultView.java b/quickstep/src/com/android/launcher3/search/ThumbnailSearchResultView.java
deleted file mode 100644
index 7108d63..0000000
--- a/quickstep/src/com/android/launcher3/search/ThumbnailSearchResultView.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.search;
-
-
-import android.app.search.SearchTarget;
-import android.content.Context;
-import android.util.AttributeSet;
-
-import java.util.List;
-
-/**
- * A view representing a high confidence app search result that includes shortcuts
- */
-public class ThumbnailSearchResultView extends androidx.appcompat.widget.AppCompatImageView
-        implements SearchTargetHandler {
-
-    public ThumbnailSearchResultView(Context context) {
-        super(context);
-    }
-
-    public ThumbnailSearchResultView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public ThumbnailSearchResultView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @Override
-    public void applySearchTarget(SearchTarget parentTarget, List<SearchTarget> children) {
-
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index 7be1b92..bdf7f8a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -22,13 +22,22 @@
 import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
 import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
 
+import android.animation.Animator;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.view.Gravity;
 import android.view.WindowManager;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.QuickstepAppTransitionManagerImpl;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AlphaUpdateListener;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.states.StateAnimationConfig;
+import com.android.quickstep.AnimatedFloat;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
 /**
@@ -44,7 +53,10 @@
     private final WindowManager mWindowManager;
     // Layout width and height of the Taskbar in the default state.
     private final Point mTaskbarSize;
+    private final TaskbarStateHandler mTaskbarStateHandler;
+    private final TaskbarVisibilityController mTaskbarVisibilityController;
 
+    // Initialized in init().
     private WindowManager.LayoutParams mWindowLayoutParams;
 
     public TaskbarController(BaseQuickstepLauncher launcher,
@@ -55,6 +67,24 @@
         mWindowManager = mLauncher.getWindowManager();
         mTaskbarSize = new Point(MATCH_PARENT,
                 mLauncher.getResources().getDimensionPixelSize(R.dimen.taskbar_size));
+        mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
+        mTaskbarVisibilityController = new TaskbarVisibilityController(mLauncher,
+                createTaskbarVisibilityControllerCallbacks());
+    }
+
+    private TaskbarVisibilityControllerCallbacks createTaskbarVisibilityControllerCallbacks() {
+        return new TaskbarVisibilityControllerCallbacks() {
+            @Override
+            public void updateTaskbarBackgroundAlpha(float alpha) {
+                mTaskbarView.setBackgroundAlpha(alpha);
+            }
+
+            @Override
+            public void updateTaskbarVisibilityAlpha(float alpha) {
+                mTaskbarContainerView.setAlpha(alpha);
+                AlphaUpdateListener.updateVisibility(mTaskbarContainerView);
+            }
+        };
     }
 
     /**
@@ -62,6 +92,17 @@
      */
     public void init() {
         addToWindowManager();
+        mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks());
+        mTaskbarVisibilityController.init();
+    }
+
+    private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() {
+        return new TaskbarStateHandlerCallbacks() {
+            @Override
+            public AnimatedFloat getAlphaTarget() {
+                return mTaskbarVisibilityController.getTaskbarVisibilityForLauncherState();
+            }
+        };
     }
 
     /**
@@ -69,6 +110,8 @@
      */
     public void cleanup() {
         removeFromWindowManager();
+        mTaskbarStateHandler.setTaskbarCallbacks(null);
+        mTaskbarVisibilityController.cleanup();
     }
 
     private void removeFromWindowManager() {
@@ -108,4 +151,58 @@
 
         mWindowManager.addView(mTaskbarContainerView, mWindowLayoutParams);
     }
+
+    /**
+     * Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
+     */
+    public void onLauncherResumedOrPaused(boolean isResumed) {
+        long duration = QuickstepAppTransitionManagerImpl.CONTENT_ALPHA_DURATION;
+        final Animator anim;
+        if (isResumed) {
+            anim = createAnimToLauncher(null, duration);
+        } else {
+            anim = createAnimToApp(duration);
+        }
+        anim.start();
+    }
+
+    /**
+     * Create Taskbar animation when going from an app to Launcher.
+     * @param toState If known, the state we will end up in when reaching Launcher.
+     */
+    public Animator createAnimToLauncher(@Nullable LauncherState toState, long duration) {
+        PendingAnimation anim = new PendingAnimation(duration);
+        anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(0, duration));
+        if (toState != null) {
+            mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim);
+        }
+        return anim.buildAnim();
+    }
+
+    private Animator createAnimToApp(long duration) {
+        return mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration);
+    }
+
+    /**
+     * Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
+     */
+    public void setIsImeVisible(boolean isImeVisible) {
+        mTaskbarVisibilityController.animateToVisibilityForIme(isImeVisible ? 0 : 1);
+    }
+
+    /**
+     * Contains methods that TaskbarStateHandler can call to interface with TaskbarController.
+     */
+    protected interface TaskbarStateHandlerCallbacks {
+        AnimatedFloat getAlphaTarget();
+    }
+
+    /**
+     * Contains methods that TaskbarVisibilityController can call to interface with
+     * TaskbarController.
+     */
+    protected interface TaskbarVisibilityControllerCallbacks {
+        void updateTaskbarBackgroundAlpha(float alpha);
+        void updateTaskbarVisibilityAlpha(float alpha);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
new file mode 100644
index 0000000..b4b5d8b
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
@@ -0,0 +1,77 @@
+/*
+ * 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.taskbar;
+
+import static com.android.launcher3.LauncherState.TASKBAR;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_TASKBAR_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_TASKBAR;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.states.StateAnimationConfig;
+import com.android.quickstep.AnimatedFloat;
+
+/**
+ * StateHandler to animate Taskbar according to Launcher's state machine. Does nothing if Taskbar
+ * isn't present (i.e. {@link #setTaskbarCallbacks} is never called).
+ */
+public class TaskbarStateHandler implements StateManager.StateHandler<LauncherState> {
+
+    private final BaseQuickstepLauncher mLauncher;
+
+    // Contains Taskbar-related methods and fields we should aniamte. If null, don't do anything.
+    private @Nullable TaskbarController.TaskbarStateHandlerCallbacks mTaskbarCallbacks = null;
+
+    public TaskbarStateHandler(BaseQuickstepLauncher launcher) {
+        mLauncher = launcher;
+    }
+
+    public void setTaskbarCallbacks(TaskbarController.TaskbarStateHandlerCallbacks callbacks) {
+        mTaskbarCallbacks = callbacks;
+    }
+
+    @Override
+    public void setState(LauncherState state) {
+        if (mTaskbarCallbacks == null) {
+            return;
+        }
+
+        AnimatedFloat alphaTarget = mTaskbarCallbacks.getAlphaTarget();
+        boolean isTaskbarVisible = (state.getVisibleElements(mLauncher) & TASKBAR) != 0;
+        alphaTarget.updateValue(isTaskbarVisible ? 1f : 0f);
+    }
+
+    @Override
+    public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
+            PendingAnimation animation) {
+        if (mTaskbarCallbacks == null) {
+            return;
+        }
+        if (config.hasAnimationFlag(SKIP_TASKBAR)) {
+            return;
+        }
+
+        AnimatedFloat alphaTarget = mTaskbarCallbacks.getAlphaTarget();
+        boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
+        animation.setFloat(alphaTarget, AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f,
+                config.getInterpolator(ANIM_TASKBAR_FADE, Interpolators.LINEAR));
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 5df8d5f..bf6e946 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar;
 
 import android.content.Context;
+import android.graphics.drawable.ColorDrawable;
 import android.util.AttributeSet;
 import android.widget.LinearLayout;
 
@@ -26,6 +27,9 @@
  * Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
  */
 public class TaskbarView extends LinearLayout {
+
+    private final ColorDrawable mBackgroundDrawable;
+
     public TaskbarView(@NonNull Context context) {
         this(context, null);
     }
@@ -42,5 +46,14 @@
     public TaskbarView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        mBackgroundDrawable = (ColorDrawable) getBackground();
+    }
+
+    /**
+     * Sets the alpha of the background color behind all the Taskbar contents.
+     * @param alpha 0 is fully transparent, 1 is fully opaque.
+     */
+    public void setBackgroundAlpha(float alpha) {
+        mBackgroundDrawable.setAlpha((int) (alpha * 255));
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java
new file mode 100644
index 0000000..4cf55d8
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java
@@ -0,0 +1,95 @@
+/*
+ * 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.taskbar;
+
+import static com.android.launcher3.LauncherState.TASKBAR;
+
+import android.animation.Animator;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.SystemUiProxy;
+import com.android.systemui.shared.system.QuickStepContract;
+
+/**
+ * Works with TaskbarController to update the TaskbarView's alpha based on LauncherState, whether
+ * Launcher is in the foreground, etc.
+ */
+public class TaskbarVisibilityController {
+
+    private static final long IME_VISIBILITY_ALPHA_DURATION = 120;
+
+    private final BaseQuickstepLauncher mLauncher;
+    private final TaskbarController.TaskbarVisibilityControllerCallbacks mTaskbarCallbacks;
+
+    // Background alpha.
+    private AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat(
+            this::onTaskbarBackgroundAlphaChanged);
+
+    // Overall visibility.
+    private AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat(
+            this::updateVisibilityAlpha);
+    private AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat(
+            this::updateVisibilityAlpha);
+
+    public TaskbarVisibilityController(BaseQuickstepLauncher launcher,
+            TaskbarController.TaskbarVisibilityControllerCallbacks taskbarCallbacks) {
+        mLauncher = launcher;
+        mTaskbarCallbacks = taskbarCallbacks;
+    }
+
+    protected void init() {
+        mTaskbarBackgroundAlpha.updateValue(mLauncher.hasBeenResumed() ? 0f : 1f);
+        boolean isVisibleForLauncherState = (mLauncher.getStateManager().getState()
+                .getVisibleElements(mLauncher) & TASKBAR) != 0;
+        mTaskbarVisibilityAlphaForLauncherState.updateValue(isVisibleForLauncherState ? 1f : 0f);
+        boolean isImeVisible = (SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags()
+                & QuickStepContract.SYSUI_STATE_IME_SHOWING) != 0;
+        mTaskbarVisibilityAlphaForIme.updateValue(isImeVisible ? 0f : 1f);
+    }
+
+    protected void cleanup() {
+    }
+
+    protected AnimatedFloat getTaskbarVisibilityForLauncherState() {
+        return mTaskbarVisibilityAlphaForLauncherState;
+    }
+
+    protected Animator createAnimToBackgroundAlpha(float toAlpha, long duration) {
+        return mTaskbarBackgroundAlpha.animateToValue(mTaskbarBackgroundAlpha.value, toAlpha)
+                .setDuration(duration);
+    }
+
+    protected void animateToVisibilityForIme(float toAlpha) {
+        mTaskbarVisibilityAlphaForIme.animateToValue(mTaskbarVisibilityAlphaForIme.value, toAlpha)
+                .setDuration(IME_VISIBILITY_ALPHA_DURATION).start();
+    }
+
+    private void onTaskbarBackgroundAlphaChanged() {
+        mTaskbarCallbacks.updateTaskbarBackgroundAlpha(mTaskbarBackgroundAlpha.value);
+        updateVisibilityAlpha();
+    }
+
+    private void updateVisibilityAlpha() {
+        // We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
+        // assumption being that Taskbar should always be visible regardless of the current
+        // LauncherState if Launcher is paused.
+        float alphaDueToLauncher = Math.max(mTaskbarBackgroundAlpha.value,
+                mTaskbarVisibilityAlphaForLauncherState.value);
+        float alphaDueToOther = mTaskbarVisibilityAlphaForIme.value;
+        mTaskbarCallbacks.updateTaskbarVisibilityAlpha(alphaDueToLauncher * alphaDueToOther);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
index 7beb9db..d14e8ef 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.Looper;
 
+import com.android.launcher3.Utilities;
 import com.android.systemui.shared.plugins.PluginInitializer;
 
 public class PluginInitializerImpl implements PluginInitializer {
@@ -44,4 +45,8 @@
     @Override
     public void handleWtfs() {
     }
+
+    public boolean isDebuggable() {
+        return Utilities.IS_DEBUG_DEVICE;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 4b4f955..2cf65af 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -69,7 +69,9 @@
     @Override
     public int getVisibleElements(Launcher launcher) {
         return super.getVisibleElements(launcher)
-                & ~OVERVIEW_BUTTONS & ~VERTICAL_SWIPE_INDICATOR;
+                & ~OVERVIEW_BUTTONS
+                & ~VERTICAL_SWIPE_INDICATOR
+                | TASKBAR;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
index 51e72da..965f474 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -40,6 +40,6 @@
 
     @Override
     public int getVisibleElements(Launcher launcher) {
-        return NONE;
+        return TASKBAR;
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index efb91c6..69b8aca 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -36,6 +36,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_TASKBAR_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
@@ -80,6 +81,7 @@
         if (toState == NORMAL && fromState == OVERVIEW) {
             config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
             config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
+            config.setInterpolator(ANIM_TASKBAR_FADE, ACCEL);
             config.setInterpolator(ANIM_ALL_APPS_FADE, ACCEL);
             config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
             config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL_DEACCEL);
@@ -138,6 +140,7 @@
             config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2);
             config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_2);
             config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, OVERSHOOT_1_2);
+            config.setInterpolator(ANIM_TASKBAR_FADE, OVERSHOOT_1_2);
         } else if (fromState == HINT_STATE && toState == NORMAL) {
             config.setInterpolator(ANIM_DEPTH, DEACCEL_3);
             if (mHintToNormalDuration == -1) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index d648dd6..6bcc4bf 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -721,11 +721,12 @@
 
     @UiThread
     public void onGestureStarted(boolean isLikelyToStartNewTask) {
-        // Temporarily disable this until we have a view that we can use
-        // InteractionJankMonitorWrapper.begin(mRecentsView,
-        //         InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timeout */);
-        // InteractionJankMonitorWrapper.begin(mRecentsView,
-        //         InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
+        if (mRecentsView != null) {
+            InteractionJankMonitorWrapper.begin(mRecentsView,
+                    InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timeout */);
+            InteractionJankMonitorWrapper.begin(mRecentsView,
+                    InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
+        }
         notifyGestureStartedAsync();
         setIsLikelyToStartNewTask(isLikelyToStartNewTask, false /* animate */);
         mStateCallback.setStateOnUiThread(STATE_GESTURE_STARTED);
@@ -970,6 +971,9 @@
                 }
                 duration = Math.max(duration, mRecentsView.getScroller().getDuration());
             }
+            if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+                mRecentsView.getRunningTaskView().setIsClickableAsLiveTile(false);
+            }
         }
 
         // Let RecentsView handle the scrolling to the task, which we launch in startNewTask()
@@ -1058,6 +1062,8 @@
         if (mGestureState.getEndTarget().isLauncher) {
             ActivityManagerWrapper.getInstance().registerTaskStackListener(
                     mActivityRestartListener);
+
+            mActivityInterface.onAnimateToLauncher(mGestureState.getEndTarget(), duration);
         }
 
         if (mGestureState.getEndTarget() == HOME) {
@@ -1447,6 +1453,10 @@
     private void finishCurrentTransitionToRecents() {
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
+            final TaskView runningTaskView = mRecentsView.getRunningTaskView();
+            if (runningTaskView != null) {
+                runningTaskView.setIsClickableAsLiveTile(true);
+            }
         } else if (!hasTargets() || mRecentsAnimationController == null) {
             // If there are no targets or the animation not started, then there is nothing to finish
             mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
diff --git a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index efd4530..d159fa0 100644
--- a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.taskbar.TaskbarController;
 import com.android.quickstep.util.RemoteAnimationProvider;
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TaskViewSimulator;
@@ -119,6 +120,11 @@
                     OVERVIEW.getDepth(mActivity), TOUCH_RESPONSE_INTERPOLATOR);
         }
 
+        TaskbarController taskbarController = mActivityInterface.getTaskbarController();
+        if (taskbarController != null) {
+            pa.add(taskbarController.createAnimToLauncher(OVERVIEW, getRecentsLaunchDuration()));
+        }
+
         RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets,
                 wallpaperTargets, MODE_CLOSING);
 
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 5bed929..5f6e59f 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -45,6 +45,7 @@
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.BaseState;
 import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.taskbar.TaskbarController;
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.WindowBounds;
 import com.android.quickstep.SysUINavigationMode.Mode;
@@ -121,6 +122,11 @@
         return null;
     }
 
+    @Nullable
+    public TaskbarController getTaskbarController() {
+        return null;
+    }
+
     public final boolean isResumed() {
         ACTIVITY_TYPE activity = getCreatedActivity();
         return activity != null && activity.hasBeenResumed();
@@ -276,6 +282,20 @@
         return overviewActionsHeight;
     }
 
+    /**
+     * Called when the gesture ends and the animation starts towards the given target. No-op by
+     * default, but subclasses can override to add an additional animation with the same duration.
+     */
+    public void onAnimateToLauncher(GestureState.GestureEndTarget endTarget, long duration) {
+    }
+
+    /**
+     * See {@link com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags}
+     * @param systemUiStateFlags The latest SystemUiStateFlags
+     */
+    public void onSystemUiFlagsChanged(int systemUiStateFlags) {
+    }
+
     public interface AnimationFactory {
 
         void createActivityInterface(long transitionLength);
diff --git a/quickstep/src/com/android/quickstep/ImageActionsApi.java b/quickstep/src/com/android/quickstep/ImageActionsApi.java
index b04905c..cb4d53a 100644
--- a/quickstep/src/com/android/quickstep/ImageActionsApi.java
+++ b/quickstep/src/com/android/quickstep/ImageActionsApi.java
@@ -83,8 +83,8 @@
      * Share the image this api was constructed with.
      */
     @UiThread
-    public void startShareActivity() {
-        ImageActionUtils.startShareActivity(mContext, mBitmapSupplier, null, null, TAG);
+    public void startShareActivity(Rect crop) {
+        ImageActionUtils.startShareActivity(mContext, mBitmapSupplier, crop, null, TAG);
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 7630bc4..deb86ec 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -16,9 +16,11 @@
 package com.android.quickstep;
 
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.quickstep.SysUINavigationMode.getMode;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -38,8 +40,10 @@
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
 import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.taskbar.TaskbarController;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.quickstep.GestureState.GestureEndTarget;
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
@@ -156,6 +160,16 @@
 
     @Nullable
     @Override
+    public TaskbarController getTaskbarController() {
+        BaseQuickstepLauncher launcher = getCreatedActivity();
+        if (launcher == null) {
+            return null;
+        }
+        return launcher.getTaskbarController();
+    }
+
+    @Nullable
+    @Override
     public RecentsView getVisibleRecentsView() {
         Launcher launcher = getVisibleLauncher();
         return launcher != null && launcher.getStateManager().getState().overviewUi
@@ -277,4 +291,24 @@
         if (activity == null) return;
         activity.getAppTransitionManager().registerRemoteTransitions();
     }
+
+    @Override
+    public void onAnimateToLauncher(GestureEndTarget endTarget, long duration) {
+        TaskbarController taskbarController = getTaskbarController();
+        if (taskbarController == null) {
+            return;
+        }
+        LauncherState toState = endTarget == GestureEndTarget.RECENTS ? OVERVIEW : NORMAL;
+        taskbarController.createAnimToLauncher(toState, duration).start();
+    }
+
+    @Override
+    public void onSystemUiFlagsChanged(int systemUiStateFlags) {
+        TaskbarController taskbarController = getTaskbarController();
+        if (taskbarController == null) {
+            return;
+        }
+        boolean isImeVisible = (systemUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0;
+        taskbarController.setIsImeVisible(isImeVisible);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
index 80308a5..65847f1 100644
--- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -26,6 +26,7 @@
 import com.android.launcher3.MainProcessInitializer;
 import com.android.launcher3.util.Executors;
 import com.android.quickstep.logging.SettingsChangeLogger;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.ThreadedRendererCompat;
 
 @SuppressWarnings("unused")
@@ -35,7 +36,11 @@
     private static final String TAG = "QuickstepProcessInitializer";
     private static final int SETUP_DELAY_MILLIS = 5000;
 
-    public QuickstepProcessInitializer(Context context) { }
+    public QuickstepProcessInitializer(Context context) {
+        // Fake call to create an instance of InteractionJankMonitor to avoid binder calls during
+        // its initialization during transitions.
+        InteractionJankMonitorWrapper.cancel(-1);
+    }
 
     @Override
     protected void init(Context context) {
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 6f2f86e..02c2763 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -21,7 +21,10 @@
 import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
 import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
 
+import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
+import android.os.SystemProperties;
 import android.util.Log;
 
 import androidx.annotation.UiThread;
@@ -30,11 +33,15 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.RemoteTransitionCompat;
 
 import java.util.function.Consumer;
 
 public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
+    public static final boolean ENABLE_SHELL_TRANSITIONS =
+            SystemProperties.getBoolean("persist.debug.shell_transit", false);
 
     private RecentsAnimationController mController;
     private RecentsAnimationCallbacks mCallbacks;
@@ -43,7 +50,11 @@
     private GestureState mLastGestureState;
     private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
     private Consumer<RemoteAnimationTargetCompat> mLaunchOtherTaskHandler;
+    private Context mCtx;
 
+    TaskAnimationManager(Context ctx) {
+        mCtx = ctx;
+    }
     /**
      * Preloads the recents animation.
      */
@@ -122,8 +133,16 @@
         final long eventTime = gestureState.getSwipeUpStartTimeMs();
         mCallbacks.addListener(gestureState);
         mCallbacks.addListener(listener);
-        UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
-                .startRecentsActivity(intent, eventTime, mCallbacks, null, null));
+
+        if (ENABLE_SHELL_TRANSITIONS) {
+            RemoteTransitionCompat transition = new RemoteTransitionCompat(mCallbacks,
+                    mController != null ? mController.getController() : null);
+            Bundle options = ActivityOptionsCompat.makeRemoteTransition(transition).toBundle();
+            mCtx.startActivity(intent, options);
+        } else {
+            UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
+                    .startRecentsActivity(intent, eventTime, mCallbacks, null, null));
+        }
         gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED);
         return mCallbacks;
     }
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 6677724..93ebd5a 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -159,7 +159,7 @@
                     @Override
                     public void onShare() {
                         if (isAllowedByPolicy) {
-                            endLiveTileMode(mImageApi::startShareActivity);
+                            endLiveTileMode(() -> mImageApi.startShareActivity(null));
                         } else {
                             showBlockedByPolicyMessage();
                         }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 196cae7..a98fc1c 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -309,7 +309,7 @@
 
     @UiThread
     public void onUserUnlocked() {
-        mTaskAnimationManager = new TaskAnimationManager();
+        mTaskAnimationManager = new TaskAnimationManager(this);
         mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
         mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState,
                 mOverviewComponentObserver);
@@ -370,12 +370,14 @@
     @UiThread
     private void onSystemUiFlagsChanged() {
         if (mDeviceState.isUserUnlocked()) {
-            SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(
-                    mDeviceState.getSystemUiStateFlags());
+            int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
+            SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
             mOverviewComponentObserver.onSystemUiStateChanged();
+            mOverviewComponentObserver.getActivityInterface().onSystemUiFlagsChanged(
+                    systemUiStateFlags);
 
             // Update the tracing state
-            if ((mDeviceState.getSystemUiStateFlags() & SYSUI_STATE_TRACING_ENABLED) != 0) {
+            if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) {
                 Log.d(TAG, "Starting tracing.");
                 ProtoTracer.INSTANCE.get(this).start();
             } else {
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 9ee9f00..cb81d36 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -27,6 +27,7 @@
 
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.allapps.AllAppsInsetTransitionController;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.hybridhotseat.HotseatPredictionController;
 import com.android.launcher3.search.DeviceSearchEdu;
@@ -139,8 +140,12 @@
                 @Override
                 public void onStateTransitionStart(LauncherState toState) {
                     if (toState == ALL_APPS) {
-                        mLauncher.getAllAppsController().getInsetController().setSearchEduRunnable(
-                                () -> DeviceSearchEdu.show(launcher));
+                        AllAppsInsetTransitionController insetTransitionController =
+                                mLauncher.getAllAppsController().getInsetController();
+                        insetTransitionController.setSearchEduRunnable(() -> {
+                            DeviceSearchEdu.show(launcher);
+                            insetTransitionController.setSearchEduRunnable(null);
+                        });
                         stateManager.removeStateListener(this);
                     }
                 }
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 4120331..5bae3c7 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -24,6 +24,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_TASKBAR;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -158,7 +159,8 @@
      */
     private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) {
         StateAnimationConfig config = new StateAnimationConfig();
-        config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER;
+        config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER
+                | SKIP_TASKBAR;
         config.duration = 0;
         // setRecentsAttachedToAppWindow() will animate recents out.
         launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start();
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index b791d29..e8f590f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -257,6 +257,8 @@
     private final float[] mIconCenterCoords = new float[2];
     private final float[] mChipCenterCoords = new float[2];
 
+    private boolean mIsClickableAsLiveTile = true;
+
     public TaskView(Context context) {
         this(context, null);
     }
@@ -273,6 +275,11 @@
                 return;
             }
             if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
+                if (!mIsClickableAsLiveTile) {
+                    return;
+                }
+
+                mIsClickableAsLiveTile = false;
                 RecentsView recentsView = getRecentsView();
                 RemoteAnimationTargets targets = recentsView.getLiveTileParams().getTargetSet();
                 recentsView.getLiveTileTaskViewSimulator().setDrawsBelowRecents(false);
@@ -289,6 +296,7 @@
                     public void onAnimationEnd(Animator animator) {
                         recentsView.getLiveTileTaskViewSimulator().setDrawsBelowRecents(true);
                         recentsView.finishRecentsAnimation(false, null);
+                        mIsClickableAsLiveTile = true;
                     }
                 });
                 anim.start();
@@ -348,6 +356,10 @@
         return false;
     }
 
+    public void setIsClickableAsLiveTile(boolean isClickableAsLiveTile) {
+        mIsClickableAsLiveTile = isClickableAsLiveTile;
+    }
+
     private void computeAndSetIconTouchDelegate() {
         float iconHalfSize = mIconView.getWidth() / 2f;
         mIconCenterCoords[0] = mIconCenterCoords[1] = iconHalfSize;
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 22eb15a..575d6cd 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -301,7 +301,7 @@
         verifyHighRes();
 
         if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
-            applyProgressLevel(info.getProgressLevel());
+            applyProgressLevel();
         }
         applyDotState(info, false /* animate */);
     }
@@ -603,21 +603,20 @@
      * with the total download progress.
      */
     public void applyLoadingState(boolean promiseStateChanged) {
-        if (getTag() instanceof WorkspaceItemInfo) {
+        if (getTag() instanceof ItemInfoWithIcon) {
             WorkspaceItemInfo info = (WorkspaceItemInfo) getTag();
-            int progressLevel = info.getProgressLevel();
             if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE)
                     != 0) {
-                updateProgressBarUi(progressLevel, progressLevel == 100);
+                updateProgressBarUi(info.getProgressLevel() == 100);
             } else if (info.hasPromiseIconUi() || (info.runtimeStatusFlags
-                    & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
-                updateProgressBarUi(progressLevel, promiseStateChanged);
+                        & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
+                updateProgressBarUi(promiseStateChanged);
             }
         }
     }
 
-    private void updateProgressBarUi(int progressLevel, boolean maybePerformFinishedAnimation) {
-        PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel);
+    private void updateProgressBarUi(boolean maybePerformFinishedAnimation) {
+        PreloadIconDrawable preloadDrawable = applyProgressLevel();
         if (preloadDrawable != null && maybePerformFinishedAnimation) {
             preloadDrawable.maybePerformFinishedAnimation();
         }
@@ -625,38 +624,59 @@
 
     /** Applies the given progress level to the this icon's progress bar. */
     @Nullable
-    public PreloadIconDrawable applyProgressLevel(int progressLevel) {
-        if (getTag() instanceof ItemInfoWithIcon) {
-            ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
-            if (progressLevel >= 100) {
-                setContentDescription(info.contentDescription != null
-                        ? info.contentDescription : "");
-            } else if (progressLevel > 0) {
-                setContentDescription(getContext()
-                        .getString(R.string.app_downloading_title, info.title,
-                                NumberFormat.getPercentInstance().format(progressLevel * 0.01)));
+    public PreloadIconDrawable applyProgressLevel() {
+        if (!(getTag() instanceof ItemInfoWithIcon)) {
+            return null;
+        }
+
+        ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
+        int progressLevel = info.getProgressLevel();
+        if (progressLevel >= 100) {
+            setContentDescription(info.contentDescription != null
+                    ? info.contentDescription : "");
+        } else if (progressLevel > 0) {
+            setContentDescription(getContext()
+                    .getString(R.string.app_downloading_title, info.title,
+                            NumberFormat.getPercentInstance().format(progressLevel * 0.01)));
+        } else {
+            setContentDescription(getContext()
+                    .getString(R.string.app_waiting_download_title, info.title));
+        }
+        if (mIcon != null) {
+            PreloadIconDrawable preloadIconDrawable;
+            if (mIcon instanceof PreloadIconDrawable) {
+                preloadIconDrawable = (PreloadIconDrawable) mIcon;
+                preloadIconDrawable.setLevel(progressLevel);
+                preloadIconDrawable.setIsDisabled(!info.isAppStartable());
             } else {
-                setContentDescription(getContext()
-                        .getString(R.string.app_waiting_download_title, info.title));
+                preloadIconDrawable = makePreloadIcon();
+                setIcon(preloadIconDrawable);
             }
-            if (mIcon != null) {
-                final PreloadIconDrawable preloadDrawable;
-                if (mIcon instanceof PreloadIconDrawable) {
-                    preloadDrawable = (PreloadIconDrawable) mIcon;
-                    preloadDrawable.setLevel(progressLevel);
-                    preloadDrawable.setIsDisabled(!info.isAppStartable());
-                } else {
-                    preloadDrawable = newPendingIcon(getContext(), info);
-                    preloadDrawable.setLevel(progressLevel);
-                    preloadDrawable.setIsDisabled(!info.isAppStartable());
-                    setIcon(preloadDrawable);
-                }
-                return preloadDrawable;
-            }
+            return preloadIconDrawable;
         }
         return null;
     }
 
+    /**
+     * Creates a PreloadIconDrawable with the appropriate progress level without mutating this
+     * object.
+     */
+    @Nullable
+    public PreloadIconDrawable makePreloadIcon() {
+        if (!(getTag() instanceof ItemInfoWithIcon)) {
+            return null;
+        }
+
+        ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
+        int progressLevel = info.getProgressLevel();
+        final PreloadIconDrawable preloadDrawable = newPendingIcon(getContext(), info);
+
+        preloadDrawable.setLevel(progressLevel);
+        preloadDrawable.setIsDisabled(!info.isAppStartable());
+
+        return preloadDrawable;
+    }
+
     public void applyDotState(ItemInfo itemInfo, boolean animate) {
         if (mIcon instanceof FastBitmapDrawable) {
             boolean wasDotted = mDotInfo != null;
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 12ce9f3..f681d75 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -607,8 +607,9 @@
      */
     public boolean updateIsSeascape(Context context) {
         if (isVerticalBarLayout()) {
-            boolean isSeascape = DisplayController.getDefaultDisplay(context).getInfo().rotation
-                    == Surface.ROTATION_270;
+            // Check an up-to-date info.
+            boolean isSeascape = DisplayController.getDefaultDisplay(context)
+                    .createInfoForContext(context).rotation == Surface.ROTATION_270;
             if (mIsSeascape != isSeascape) {
                 mIsSeascape = isSeascape;
                 return true;
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 139d4a8..b1fe4a2 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -276,15 +276,15 @@
 
     @Override
     public ConstantState getConstantState() {
-        return new MyConstantState(mBitmap, mIconColor, mIsDisabled);
+        return new FastBitmapConstantState(mBitmap, mIconColor, mIsDisabled);
     }
 
-    protected static class MyConstantState extends ConstantState {
+    protected static class FastBitmapConstantState extends ConstantState {
         protected final Bitmap mBitmap;
         protected final int mIconColor;
         protected final boolean mIsDisabled;
 
-        public MyConstantState(Bitmap bitmap, int color, boolean isDisabled) {
+        public FastBitmapConstantState(Bitmap bitmap, int color, boolean isDisabled) {
             mBitmap = bitmap;
             mIconColor = color;
             mIsDisabled = isDisabled;
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 79476fc..f9a1ded 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -57,6 +57,7 @@
     public static final int ALL_APPS_CONTENT = 1 << 4;
     public static final int VERTICAL_SWIPE_INDICATOR = 1 << 5;
     public static final int OVERVIEW_BUTTONS = 1 << 6;
+    public static final int TASKBAR = 1 << 7;
 
     /** Mask of all the items that are contained in the apps view. */
     public static final int APPS_VIEW_ITEM_MASK =
@@ -186,7 +187,7 @@
     }
 
     public int getVisibleElements(Launcher launcher) {
-        int flags = HOTSEAT_ICONS | VERTICAL_SWIPE_INDICATOR;
+        int flags = HOTSEAT_ICONS | VERTICAL_SWIPE_INDICATOR | TASKBAR;
         if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()
                 && !launcher.getDeviceProfile().isVerticalBarLayout()) {
             flags |= HOTSEAT_SEARCH_BOX;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 8066aa6..51d8e66 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -67,7 +67,7 @@
 import androidx.core.os.BuildCompat;
 
 import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
-import com.android.launcher3.graphics.GridOptionsProvider;
+import com.android.launcher3.graphics.GridCustomizationsProvider;
 import com.android.launcher3.graphics.TintedDrawableSpan;
 import com.android.launcher3.icons.IconProvider;
 import com.android.launcher3.icons.LauncherIcons;
@@ -520,7 +520,7 @@
     public static boolean isGridOptionsEnabled(Context context) {
         return isComponentEnabled(context.getPackageManager(),
                 context.getPackageName(),
-                GridOptionsProvider.class.getName());
+                GridCustomizationsProvider.class.getName());
     }
 
     private static boolean isComponentEnabled(PackageManager pm, String pkgName, String clsName) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 65eba20..8a45c81 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -111,9 +111,11 @@
 import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * The workspace is a wide area with a wallpaper and a finite number of pages.
@@ -3002,38 +3004,27 @@
      * shortcuts are not removed.
      */
     public void removeItemsByMatcher(final ItemInfoMatcher matcher) {
-        for (final CellLayout layoutParent: getWorkspaceAndHotseatCellLayouts()) {
-            final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
+        for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
+            ShortcutAndWidgetContainer container = layout.getShortcutsAndWidgets();
+            // Iterate in reverse order as we are removing items
+            for (int i = container.getChildCount() - 1; i >= 0; i--) {
+                View child = container.getChildAt(i);
+                ItemInfo info = (ItemInfo) child.getTag();
 
-            IntSparseArrayMap<View> idToViewMap = new IntSparseArrayMap<>();
-            ArrayList<ItemInfo> items = new ArrayList<>();
-            for (int j = 0; j < layout.getChildCount(); j++) {
-                final View view = layout.getChildAt(j);
-                if (view.getTag() instanceof ItemInfo) {
-                    ItemInfo item = (ItemInfo) view.getTag();
-                    items.add(item);
-                    idToViewMap.put(item.id, view);
-                }
-            }
-
-            for (ItemInfo itemToRemove : matcher.filterItemInfos(items)) {
-                View child = idToViewMap.get(itemToRemove.id);
-
-                if (child != null) {
-                    // Note: We can not remove the view directly from CellLayoutChildren as this
-                    // does not re-mark the spaces as unoccupied.
-                    layoutParent.removeViewInLayout(child);
+                if (matcher.matchesInfo(info)) {
+                    layout.removeViewInLayout(child);
                     if (child instanceof DropTarget) {
                         mDragController.removeDropTarget((DropTarget) child);
                     }
-                } else if (itemToRemove.container >= 0) {
-                    // The item may belong to a folder.
-                    View parent = idToViewMap.get(itemToRemove.container);
-                    if (parent instanceof FolderIcon) {
-                        FolderInfo folderInfo = (FolderInfo) parent.getTag();
-                        folderInfo.remove((WorkspaceItemInfo) itemToRemove, false);
-                        if (((FolderIcon) parent).getFolder().isOpen()) {
-                            ((FolderIcon) parent).getFolder().close(false /* animate */);
+                } else if (child instanceof FolderIcon) {
+                    FolderInfo folderInfo = (FolderInfo) info;
+                    List<WorkspaceItemInfo> matches = folderInfo.contents.stream()
+                            .filter(matcher::matchesInfo)
+                            .collect(Collectors.toList());
+                    if (!matches.isEmpty()) {
+                        folderInfo.removeAll(matches, false);
+                        if (((FolderIcon) child).getFolder().isOpen()) {
+                            ((FolderIcon) child).getFolder().close(false /* animate */);
                         }
                     }
                 }
@@ -3143,9 +3134,8 @@
     }
 
     public void removeAbandonedPromise(String packageName, UserHandle user) {
-        HashSet<String> packages = new HashSet<>(1);
-        packages.add(packageName);
-        ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packages, user);
+        ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(
+                Collections.singleton(packageName), user);
         mLauncher.getModelWriter().deleteItemsFromDatabase(matcher);
         removeItemsByMatcher(matcher);
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 00bdb70..769cb5e 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -154,7 +154,7 @@
     public void updateProgressBar(AppInfo app) {
         updateAllIcons((child) -> {
             if (child.getTag() == app) {
-                child.applyProgressLevel(app.getProgressLevel());
+                child.applyProgressLevel();
             }
         });
     }
diff --git a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
index 511de30..a79ec43 100644
--- a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.allapps.search;
 
-
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 63fa391..61938d1 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -1394,10 +1394,10 @@
         mItemsInvalidated = true;
     }
 
-    public void onRemove(WorkspaceItemInfo item) {
+    @Override
+    public void onRemove(List<WorkspaceItemInfo> items) {
         mItemsInvalidated = true;
-        View v = getViewForInfo(item);
-        mContent.removeItem(v);
+        items.stream().map(this::getViewForInfo).forEach(mContent::removeItem);
         if (mState == STATE_ANIMATING) {
             mRearrangeOnClose = true;
         } else {
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 3296eed..fe310f6 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -695,9 +695,9 @@
     }
 
     @Override
-    public void onRemove(WorkspaceItemInfo item) {
+    public void onRemove(List<WorkspaceItemInfo> items) {
         boolean wasDotted = mDotInfo.hasDot();
-        mDotInfo.subtractDotInfo(mActivity.getDotInfoForItem(item));
+        items.stream().map(mActivity::getDotInfoForItem).forEach(mDotInfo::subtractDotInfo);
         boolean isDotted = mDotInfo.hasDot();
         updateDotScale(wasDotted, isDotted);
         setContentDescription(getAccessiblityTitle(mInfo.title));
diff --git a/src/com/android/launcher3/graphics/GridOptionsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
similarity index 97%
rename from src/com/android/launcher3/graphics/GridOptionsProvider.java
rename to src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 08d7e4c..cb42e7a 100644
--- a/src/com/android/launcher3/graphics/GridOptionsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -40,9 +40,9 @@
  *     /default_grid: Call update to set the current grid, with values
  *          name: name of the grid to apply
  */
-public class GridOptionsProvider extends ContentProvider {
+public class GridCustomizationsProvider extends ContentProvider {
 
-    private static final String TAG = "GridOptionsProvider";
+    private static final String TAG = "GridCustomizationsProvider";
 
     private static final String KEY_NAME = "name";
     private static final String KEY_ROWS = "rows";
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index 9971990..304d496 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -105,6 +105,10 @@
     private ObjectAnimator mCurrentAnim;
 
     public PreloadIconDrawable(ItemInfoWithIcon info, Context context) {
+        this(info, IconPalette.getPreloadProgressColor(context, info.bitmap.color));
+    }
+
+    public PreloadIconDrawable(ItemInfoWithIcon info, int indicatorColor) {
         super(info.bitmap);
         mItem = info;
         mShapePath = getShapePath();
@@ -114,7 +118,7 @@
         mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
         mProgressPaint.setStyle(Paint.Style.STROKE);
         mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
-        mIndicatorColor = IconPalette.getPreloadProgressColor(context, mIconColor);
+        mIndicatorColor = indicatorColor;
 
         setInternalProgress(0);
 
@@ -297,4 +301,42 @@
     public static PreloadIconDrawable newPendingIcon(Context context, ItemInfoWithIcon info) {
         return new PreloadIconDrawable(info, context);
     }
+
+    @Override
+    public ConstantState getConstantState() {
+        return new PreloadIconConstantState(
+                mBitmap, mIconColor, !mItem.isAppStartable(), mItem, mIndicatorColor);
+    }
+
+    protected static class PreloadIconConstantState extends FastBitmapConstantState {
+
+        protected final ItemInfoWithIcon mInfo;
+        protected final int mIndicatorColor;
+        protected final int mLevel;
+
+        public PreloadIconConstantState(
+                Bitmap bitmap,
+                int iconColor,
+                boolean isDisabled,
+                ItemInfoWithIcon info,
+                int indicatorcolor) {
+            super(bitmap, iconColor, isDisabled);
+            mInfo = info;
+            mIndicatorColor = indicatorcolor;
+            mLevel = info.getProgressLevel();
+        }
+
+        @Override
+        public PreloadIconDrawable newDrawable() {
+            PreloadIconDrawable drawable = new PreloadIconDrawable(mInfo, mIndicatorColor);
+            drawable.setLevel(mLevel);
+            drawable.setIsDisabled(mIsDisabled);
+            return drawable;
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return 0;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/icons/ClockDrawableWrapper.java b/src/com/android/launcher3/icons/ClockDrawableWrapper.java
index b7dd092..1bd252b 100644
--- a/src/com/android/launcher3/icons/ClockDrawableWrapper.java
+++ b/src/com/android/launcher3/icons/ClockDrawableWrapper.java
@@ -308,7 +308,7 @@
             return new ClockConstantState(mInfo, isDisabled());
         }
 
-        private static class ClockConstantState extends MyConstantState {
+        private static class ClockConstantState extends FastBitmapConstantState {
 
             private final ClockBitmapInfo mInfo;
 
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index f74c8b5..8438622 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -588,27 +588,26 @@
                                 if (isSafeMode && !isSystemApp(context, intent)) {
                                     info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
                                 }
+                                    LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();
+                                    if (activityInfo != null) {
+                                        info.setProgressLevel(
+                                                PackageManagerHelper
+                                                    .getLoadingProgress(activityInfo),
+                                                PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+                                    }
 
                                 if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
                                     tempPackageKey.update(targetPkg, c.user);
                                     SessionInfo si = installingPkgs.get(tempPackageKey);
-                                        LauncherActivityInfo activityInfo =
-                                                c.getLauncherActivityInfo();
                                         if (si == null) {
                                             info.runtimeStatusFlags &=
-                                                    ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+                                                ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
                                         } else if (activityInfo == null) {
                                             int installProgress = (int) (si.getProgress() * 100);
 
                                             info.setProgressLevel(
                                                     installProgress,
                                                     PackageInstallInfo.STATUS_INSTALLING);
-                                        } else {
-                                            info.setProgressLevel(
-                                                    PackageManagerHelper
-                                                            .getLoadingProgress(activityInfo),
-                                                    PackageInstallInfo
-                                                            .STATUS_INSTALLED_DOWNLOADING);
                                         }
                                 }
 
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 2c99df7..f7b43d6 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -51,6 +51,7 @@
 import java.util.concurrent.Executor;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
 
 /**
  * Class for handling model updates.
@@ -259,7 +260,9 @@
      * Removes all the items from the database matching {@param matcher}.
      */
     public void deleteItemsFromDatabase(ItemInfoMatcher matcher) {
-        deleteItemsFromDatabase(matcher.filterItemInfos(mBgDataModel.itemsIdMap));
+        deleteItemsFromDatabase(StreamSupport.stream(mBgDataModel.itemsIdMap.spliterator(), false)
+                        .filter(matcher::matchesInfo)
+                        .collect(Collectors.toList()));
     }
 
     /**
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index dde0cf4..7f70bad 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -179,7 +179,7 @@
         // Sets the progress level, installation and incremental download flags.
         info.setProgressLevel(
                 PackageManagerHelper.getLoadingProgress(lai),
-                PackageInstallInfo.STATUS_INSTALLED);
+                PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
     }
 
     @Override
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index 06a2c92..cc783f7 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -40,6 +40,8 @@
 import com.android.launcher3.util.ContentWriter;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.OptionalInt;
 import java.util.stream.IntStream;
 
@@ -137,9 +139,16 @@
      * @param item
      */
     public void remove(WorkspaceItemInfo item, boolean animate) {
-        contents.remove(item);
+        removeAll(Collections.singletonList(item), animate);
+    }
+
+    /**
+     * Remove all matching app or shortcut. Does not change the DB.
+     */
+    public void removeAll(List<WorkspaceItemInfo> items, boolean animate) {
+        contents.removeAll(items);
         for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onRemove(item);
+            mListeners.get(i).onRemove(items);
         }
         itemsChanged(animate);
     }
@@ -166,9 +175,9 @@
     }
 
     public interface FolderListener {
-        public void onAdd(WorkspaceItemInfo item, int rank);
-        public void onRemove(WorkspaceItemInfo item);
-        public void onItemsChanged(boolean animate);
+        void onAdd(WorkspaceItemInfo item, int rank);
+        void onRemove(List<WorkspaceItemInfo> item);
+        void onItemsChanged(boolean animate);
     }
 
     public boolean hasOption(int optionFlag) {
diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
index 1831ffd..8469569 100644
--- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java
+++ b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
@@ -21,6 +21,8 @@
 import android.os.Process;
 import android.os.UserHandle;
 
+import androidx.annotation.Nullable;
+
 /**
  * Represents a SearchAction with in launcher
  */
@@ -28,9 +30,10 @@
 
     public static final int FLAG_SHOULD_START = 1 << 1;
     public static final int FLAG_SHOULD_START_FOR_RESULT = FLAG_SHOULD_START | 1 << 2;
+    public static final int FLAG_BADGE_WITH_PACKAGE = 1 << 3;
+    public static final int FLAG_PRIMARY_ICON_FROM_TITLE = 1 << 4;
 
     private final String mFallbackPackageName;
-
     private int mFlags = 0;
     private final Icon mIcon;
 
@@ -54,12 +57,15 @@
         title = info.title;
     }
 
-    public void setFlags(int flags) {
-        mFlags = flags;
+    /**
+     * Returns if multiple flags are all available.
+     */
+    public boolean hasFlags(int flags) {
+        return (mFlags & flags) != 0;
     }
 
-    public int getFlags() {
-        return mFlags;
+    public void setFlags(int flags) {
+        mFlags |= flags ;
     }
 
     @Override
@@ -93,20 +99,13 @@
         mPendingIntent = pendingIntent;
     }
 
-
-    /**
-     * Returns if a flag is set on instance
-     */
-    public boolean hasFlag(int flag) {
-        return (mFlags & flag) == flag;
+    @Nullable
+    public Icon getIcon() {
+        return mIcon;
     }
 
     @Override
     public ItemInfoWithIcon clone() {
         return new SearchActionItemInfo(this);
     }
-
-    public Icon getIcon() {
-        return mIcon;
-    }
 }
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 45172b5..44bcc34 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -90,4 +90,9 @@
     public float getWorkspaceScrimAlpha(Launcher launcher) {
         return 0.3f;
     }
+
+    @Override
+    public int getVisibleElements(Launcher launcher) {
+        return super.getVisibleElements(launcher) & ~TASKBAR;
+    }
 }
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index 8b72177..ec949eb 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -37,7 +37,8 @@
             PLAY_ATOMIC_OVERVIEW_SCALE,
             PLAY_ATOMIC_OVERVIEW_PEEK,
             SKIP_OVERVIEW,
-            SKIP_DEPTH_CONTROLLER
+            SKIP_DEPTH_CONTROLLER,
+            SKIP_TASKBAR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AnimationFlags {}
@@ -46,6 +47,7 @@
     public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2;
     public static final int SKIP_OVERVIEW = 1 << 3;
     public static final int SKIP_DEPTH_CONTROLLER = 1 << 4;
+    public static final int SKIP_TASKBAR = 1 << 5;
 
     public long duration;
     public boolean userControlled;
@@ -72,6 +74,7 @@
             ANIM_OVERVIEW_MODAL,
             ANIM_DEPTH,
             ANIM_OVERVIEW_ACTIONS_FADE,
+            ANIM_TASKBAR_FADE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AnimType {}
@@ -91,8 +94,9 @@
     public static final int ANIM_OVERVIEW_MODAL = 13;
     public static final int ANIM_DEPTH = 14;
     public static final int ANIM_OVERVIEW_ACTIONS_FADE = 15;
+    public static final int ANIM_TASKBAR_FADE = 16;
 
-    private static final int ANIM_TYPES_COUNT = 16;
+    private static final int ANIM_TYPES_COUNT = 17;
 
     protected final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
 
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index d9483e5..3122c68 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -250,7 +250,7 @@
      */
     public static void onClickSearchAction(Launcher launcher, SearchActionItemInfo itemInfo) {
         if (itemInfo.getIntent() != null) {
-            if (itemInfo.hasFlag(SearchActionItemInfo.FLAG_SHOULD_START_FOR_RESULT)) {
+            if (itemInfo.hasFlags(SearchActionItemInfo.FLAG_SHOULD_START_FOR_RESULT)) {
                 launcher.startActivityForResult(itemInfo.getIntent(), 0);
             } else {
                 launcher.startActivity(itemInfo.getIntent());
@@ -258,9 +258,9 @@
         } else if (itemInfo.getPendingIntent() != null) {
             try {
                 PendingIntent pendingIntent = itemInfo.getPendingIntent();
-                if (!itemInfo.hasFlag(SearchActionItemInfo.FLAG_SHOULD_START)) {
+                if (!itemInfo.hasFlags(SearchActionItemInfo.FLAG_SHOULD_START)) {
                     pendingIntent.send();
-                } else if (itemInfo.hasFlag(SearchActionItemInfo.FLAG_SHOULD_START_FOR_RESULT)) {
+                } else if (itemInfo.hasFlags(SearchActionItemInfo.FLAG_SHOULD_START_FOR_RESULT)) {
                     launcher.startIntentSenderForResult(pendingIntent.getIntentSender(), 0, null, 0,
                             0, 0);
                 } else {
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 355c949..3b7bcc2 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -31,6 +31,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.Utilities;
+
 import java.util.ArrayList;
 
 /**
@@ -179,23 +181,35 @@
             return mInfo;
         }
 
+        /** Creates and up-to-date DisplayController.Info for the given context. */
+        public Info createInfoForContext(Context context) {
+            Display display = Utilities.ATLEAST_R
+                    ? context.getDisplay()
+                    : context
+                        .getSystemService(DisplayManager.class)
+                        .getDisplay(mId);
+            return display == null
+                    ? new Info(context)
+                    : new Info(context, display);
+        }
+
         protected void handleOnChange() {
             Info oldInfo = mInfo;
-            Info info = new Info(mDisplayContext);
+            Info newInfo = createInfoForContext(mDisplayContext);
 
             int change = 0;
-            if (info.hasDifferentSize(oldInfo)) {
+            if (newInfo.hasDifferentSize(oldInfo)) {
                 change |= CHANGE_SIZE;
             }
-            if (oldInfo.rotation != info.rotation) {
+            if (newInfo.rotation != oldInfo.rotation) {
                 change |= CHANGE_ROTATION;
             }
-            if (info.singleFrameMs != oldInfo.singleFrameMs) {
+            if (newInfo.singleFrameMs != oldInfo.singleFrameMs) {
                 change |= CHANGE_FRAME_DELAY;
             }
 
             if (change != 0) {
-                mInfo = info;
+                mInfo = newInfo;
                 final int flags = change;
                 MAIN_EXECUTOR.execute(() -> notifyChange(flags));
             }
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index d26bb57..354609d 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -20,10 +20,7 @@
 import android.os.UserHandle;
 
 import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.shortcuts.ShortcutKey;
 
 import java.util.HashSet;
@@ -37,34 +34,15 @@
     boolean matches(ItemInfo info, ComponentName cn);
 
     /**
-     * Filters {@param infos} to those satisfying the {@link #matches(ItemInfo, ComponentName)}.
+     * Returns true if the itemInfo matches this check
      */
-    default HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
-        HashSet<ItemInfo> filtered = new HashSet<>();
-        for (ItemInfo i : infos) {
-            if (i instanceof WorkspaceItemInfo) {
-                WorkspaceItemInfo info = (WorkspaceItemInfo) i;
-                ComponentName cn = info.getTargetComponent();
-                if (cn != null && matches(info, cn)) {
-                    filtered.add(info);
-                }
-            } else if (i instanceof FolderInfo) {
-                FolderInfo info = (FolderInfo) i;
-                for (WorkspaceItemInfo s : info.contents) {
-                    ComponentName cn = s.getTargetComponent();
-                    if (cn != null && matches(s, cn)) {
-                        filtered.add(s);
-                    }
-                }
-            } else if (i instanceof LauncherAppWidgetInfo) {
-                LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;
-                ComponentName cn = info.providerName;
-                if (cn != null && matches(info, cn)) {
-                    filtered.add(info);
-                }
-            }
+    default boolean matchesInfo(ItemInfo info) {
+        if (info != null) {
+            ComponentName cn = info.getTargetComponent();
+            return cn != null && matches(info, cn);
+        } else {
+            return false;
         }
-        return filtered;
     }
 
     /**
@@ -96,7 +74,7 @@
         return (info, cn) -> components.contains(cn) && info.user.equals(user);
     }
 
-    static ItemInfoMatcher ofPackages(HashSet<String> packageNames, UserHandle user) {
+    static ItemInfoMatcher ofPackages(Set<String> packageNames, UserHandle user) {
         return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
     }
 
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 1857c5a..23c3722 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -51,8 +51,10 @@
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 
@@ -252,12 +254,26 @@
     @SuppressWarnings("WrongThread")
     private static void getIconResult(Launcher l, View originalView, ItemInfo info, RectF pos,
             IconLoadResult iconLoadResult) {
-        Drawable drawable = null;
+        Drawable drawable;
+        Drawable btvIcon;
         Drawable badge = null;
         boolean supportsAdaptiveIcons = ADAPTIVE_ICON_WINDOW_ANIM.get()
                 && !info.isDisabled(); // Use original icon for disabled icons.
-        Drawable btvIcon = originalView instanceof BubbleTextView
-                ? ((BubbleTextView) originalView).getIcon() : null;
+
+        if (originalView instanceof BubbleTextView) {
+            BubbleTextView btv = (BubbleTextView) originalView;
+
+            if (info instanceof ItemInfoWithIcon
+                    && (((ItemInfoWithIcon) info).runtimeStatusFlags
+                        & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
+                btvIcon = btv.makePreloadIcon();
+            } else {
+                btvIcon = btv.getIcon();
+            }
+        } else {
+            btvIcon = null;
+        }
+
         if (info instanceof SystemShortcut) {
             if (originalView instanceof ImageView) {
                 drawable = ((ImageView) originalView).getDrawable();
@@ -266,6 +282,9 @@
             } else {
                 drawable = originalView.getBackground();
             }
+        } else if (btvIcon instanceof PreloadIconDrawable) {
+            // Force the progress bar to display.
+            drawable = btvIcon;
         } else {
             int width = (int) pos.width();
             int height = (int) pos.height();
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTargetEventLegacy.java b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEventLegacy.java
index 7fbd6ac..0fc61f0 100644
--- a/src_plugins/com/android/systemui/plugins/shared/SearchTargetEventLegacy.java
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEventLegacy.java
@@ -20,7 +20,7 @@
 /**
  * Event used for the feedback loop to the plugin. (and future aiai)
  *
- * @deprecated Use SearchTargetEvent
+ * @deprecated Use {@link android.app.search.SearchTargetEvent}
  */
 @Deprecated
 public class SearchTargetEventLegacy {