Create icon app chip menu for overview tasks.

Fix: 257951354
Test: TaplTestsQuickstep
Test: TaplTestsSplitscreen
Flag: ENABLE_OVERVIEW_ICON_MENU
Change-Id: Id8a14b1970ae42bcc74e95419caeaf52ef63638b
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 9221f6b..874f862 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -34,3 +34,10 @@
     description: "Enables new workspace grid calculations method."
     bug: "241386436"
 }
+
+flag {
+    name: "enable_overview_icon_menu"
+    namespace: "launcher"
+    description: "Enable updated overview icon and menu within task."
+    bug: "257950105"
+}
diff --git a/quickstep/res/drawable/ic_chevron_down.xml b/quickstep/res/drawable/ic_chevron_down.xml
new file mode 100644
index 0000000..77a8295
--- /dev/null
+++ b/quickstep/res/drawable/ic_chevron_down.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <target android:name="scaleGroup">
+        <aapt:attr name="android:animation">
+            <objectAnimator
+                android:duration="150"
+                android:propertyName="scaleX"
+                android:valueFrom="1"
+                android:valueTo="-1" />
+        </aapt:attr>
+    </target>
+    <aapt:attr name="android:drawable">
+        <vector
+            android:width="48dp"
+            android:height="48dp"
+            android:autoMirrored="true"
+            android:tint="?androidprv:attr/materialColorOnSurface"
+            android:viewportHeight="48"
+            android:viewportWidth="48">
+            <group
+                android:name="scaleGroup"
+                android:pivotX="24"
+                android:pivotY="24"
+                android:rotation="90">
+                <path
+                    android:fillColor="@android:color/white"
+                    android:pathData="M18.75,36 L16.6,33.85 26.5,23.95 16.6,14.05 18.75,11.9 30.8,23.95Z" />
+            </group>
+        </vector>
+    </aapt:attr>
+</animated-vector>
diff --git a/quickstep/res/layout/icon_app_chip_view.xml b/quickstep/res/layout/icon_app_chip_view.xml
new file mode 100644
index 0000000..87519a0
--- /dev/null
+++ b/quickstep/res/layout/icon_app_chip_view.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2023 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.quickstep.views.IconAppChipView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/icon"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:focusable="false"
+    android:importantForAccessibility="no"
+    android:autoMirrored="true"
+    android:elevation="@dimen/task_thumbnail_icon_menu_elevation" >
+
+    <ImageView
+        android:id="@+id/icon_view_background"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/icon_menu_background"
+        android:importantForAccessibility="no" />
+
+    <com.android.quickstep.views.IconView
+        android:id="@+id/icon_view"
+        android:layout_width="@dimen/task_thumbnail_icon_size"
+        android:layout_height="@dimen/task_thumbnail_icon_size"
+        android:focusable="false"
+        android:importantForAccessibility="no" />
+
+    <TextView
+        android:id="@+id/icon_text"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center_vertical"
+        android:maxLines="1"
+        android:textAlignment="viewStart"
+        android:textColor="?androidprv:attr/materialColorOnSurface"
+        android:textSize="16sp"
+        android:importantForAccessibility="no" />
+
+    <ImageView
+        android:id="@+id/icon_arrow"
+        android:layout_width="@dimen/task_thumbnail_icon_menu_arrow_size"
+        android:layout_height="match_parent"
+        android:background="@drawable/icon_menu_arrow_background"
+        android:src="@drawable/ic_chevron_down"
+        android:importantForAccessibility="no" />
+</com.android.quickstep.views.IconAppChipView>
\ No newline at end of file
diff --git a/quickstep/res/layout/icon_view.xml b/quickstep/res/layout/icon_view.xml
new file mode 100644
index 0000000..a33066f
--- /dev/null
+++ b/quickstep/res/layout/icon_view.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2023 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.quickstep.views.IconView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 29c9992..823a86e 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -44,10 +44,9 @@
         android:importantForAccessibility="no"
         android:src="@drawable/ic_select_windows" />
 
-    <com.android.quickstep.views.IconView
+    <ViewStub
         android:id="@+id/icon"
-        android:layout_width="@dimen/task_thumbnail_icon_size"
-        android:layout_height="@dimen/task_thumbnail_icon_size"
-        android:focusable="false"
-        android:importantForAccessibility="no"/>
+        android:inflatedId="@id/icon"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content" />
 </com.android.quickstep.views.TaskView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 06f4d06..fe12bd3 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -45,11 +45,10 @@
         android:layout_height="wrap_content"
         android:visibility="gone" />
 
-    <com.android.quickstep.views.IconView
+    <ViewStub
         android:id="@+id/icon"
-        android:layout_width="@dimen/task_thumbnail_icon_size"
-        android:layout_height="@dimen/task_thumbnail_icon_size"
-        android:focusable="false"
-        android:importantForAccessibility="no" />
+        android:inflatedId="@id/icon"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content" />
 
 </com.android.quickstep.views.DesktopTaskView>
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index 75ff626..d20afd3 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -66,17 +66,15 @@
         android:importantForAccessibility="no"
         android:src="@drawable/ic_select_windows" />
 
-    <com.android.quickstep.views.IconView
+    <ViewStub
         android:id="@+id/icon"
-        android:layout_width="@dimen/task_thumbnail_icon_size"
-        android:layout_height="@dimen/task_thumbnail_icon_size"
-        android:focusable="false"
-        android:importantForAccessibility="no"/>
+        android:inflatedId="@id/icon"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content" />
 
-    <com.android.quickstep.views.IconView
+    <ViewStub
         android:id="@+id/bottomRight_icon"
-        android:layout_width="@dimen/task_thumbnail_icon_size"
-        android:layout_height="@dimen/task_thumbnail_icon_size"
-        android:focusable="false"
-        android:importantForAccessibility="no"/>
+        android:inflatedId="@id/bottomRight_icon"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content" />
 </com.android.quickstep.views.GroupedTaskView>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index aeb453c..aaa699b 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -44,6 +44,33 @@
     <dimen name="overview_task_margin">16dp</dimen>
     <!--  The horizontal space between tasks  -->
     <dimen name="overview_page_spacing">16dp</dimen>
+    <!--  The width of the thumbnail icon menu  -->
+    <dimen name="task_thumbnail_icon_menu_min_width">132dp</dimen>
+    <!--  The width of the icon menu text  -->
+    <dimen name="task_thumbnail_icon_menu_text_width">62dp</dimen>
+    <!--  The max width of the icon menu text  -->
+    <dimen name="task_thumbnail_icon_menu_text_max_width">138dp</dimen>
+    <!--  The max width of the thumbnail icon menu  -->
+    <dimen name="task_thumbnail_icon_menu_max_width">216dp</dimen>
+    <!--  The height of the thumbnail icon menu  -->
+    <dimen name="task_thumbnail_icon_menu_min_height">36dp</dimen>
+    <!--  The max height of the thumbnail icon menu  -->
+    <dimen name="task_thumbnail_icon_menu_max_height">52dp</dimen>
+    <!--  The size of the icon menu arrow  -->
+    <dimen name="task_thumbnail_icon_menu_arrow_size">32dp</dimen>
+    <!--  The size of the icon menu arrow drawable  -->
+    <dimen name="task_thumbnail_icon_menu_arrow_drawable_size">16dp</dimen>
+    <!--  The margin around the task icon menu  -->
+    <dimen name="task_thumbnail_icon_menu_margin">12dp</dimen>
+    <!--  The space around the task icon arrow within the icon menu  -->
+    <dimen name="task_thumbnail_icon_menu_arrow_margin">6dp</dimen>
+    <!--  The max space around the task icon within the icon menu  -->
+    <dimen name="task_thumbnail_icon_menu_touch_max_margin">8dp</dimen>
+    <!--  The icon size for the icon menu  -->
+    <dimen name="task_thumbnail_icon_menu_drawable_size">24dp</dimen>
+    <!--  The size of the icon menu's icon touch target  -->
+    <dimen name="task_thumbnail_icon_menu_drawable_touch_size">36dp</dimen>
+    <dimen name="task_thumbnail_icon_menu_elevation">14dp</dimen>
 
     <dimen name="task_icon_cache_default_icon_size">72dp</dimen>
     <item name="overview_modal_max_scale" format="float" type="dimen">1.1</item>
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index c3774eb..689402b 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -34,12 +34,12 @@
 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource
 import com.android.launcher3.views.BaseDragLayer
 import com.android.quickstep.views.FloatingTaskView
-import com.android.quickstep.views.IconView
 import com.android.quickstep.views.RecentsView
 import com.android.quickstep.views.SplitInstructionsView
 import com.android.quickstep.views.TaskThumbnailView
 import com.android.quickstep.views.TaskView
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskViewIcon
 import java.util.function.Supplier
 
 /**
@@ -82,7 +82,7 @@
                     return SplitAnimInitProps(container.thumbnailView,
                             container.thumbnailView.thumbnail, drawable!!,
                             fadeWithThumbnail = true, isStagedTask = true,
-                            iconView = container.iconView
+                            iconView = container.iconView.asView()
                     )
                 }
             }
@@ -94,7 +94,7 @@
             val drawable = getDrawable(taskView.iconView, splitSelectSource)
             return SplitAnimInitProps(taskView.thumbnail, taskView.thumbnail.thumbnail,
                     drawable!!, fadeWithThumbnail = true, isStagedTask = true,
-                    taskView.iconView
+                    taskView.iconView.asView()
             )
         }
     }
@@ -105,7 +105,7 @@
      * TaskView's icon drawable can be null if the TaskView is scrolled far enough off screen
      * @return [Drawable]
      */
-    fun getDrawable(iconView: IconView, splitSelectSource: SplitSelectSource?) : Drawable? {
+    fun getDrawable(iconView: TaskViewIcon, splitSelectSource: SplitSelectSource?) : Drawable? {
         if (iconView.drawable == null && splitSelectSource != null) {
             return splitSelectSource.drawable
         }
@@ -129,7 +129,7 @@
                                 taskViewWidth: Int, taskViewHeight: Int,
                                 isPrimaryTaskSplitting: Boolean) {
         val thumbnail = taskIdAttributeContainer.thumbnailView
-        val iconView: View = taskIdAttributeContainer.iconView
+        val iconView: View = taskIdAttributeContainer.iconView.asView()
         builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLASH_ALPHA, 1f))
         thumbnail.setShowSplashForSplitSelection(true)
         if (deviceProfile.isLandscape) {
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 8a6c197..dc6b5a2 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -330,7 +330,7 @@
     }
 
     @Override
-    protected boolean showTaskMenuWithContainer(IconView iconView) {
+    protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
         return false;
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 2e347ba..3d33c87 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -2,6 +2,7 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.quickstep.util.SplitScreenUtils.convertLauncherSplitBoundsToShell;
 
@@ -11,6 +12,7 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewStub;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -25,6 +27,7 @@
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TaskIconCache;
 import com.android.quickstep.TaskThumbnailCache;
+import com.android.quickstep.TaskUtils;
 import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.SplitSelectStateController;
@@ -54,7 +57,7 @@
     @Nullable
     private Task mSecondaryTask;
     private TaskThumbnailView mSnapshotView2;
-    private IconView mIconView2;
+    private TaskViewIcon mIconView2;
     @Nullable
     private CancellableTask<ThumbnailData> mThumbnailLoadRequest2;
     @Nullable
@@ -99,8 +102,14 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mSnapshotView2 = findViewById(R.id.bottomright_snapshot);
-        mIconView2 = findViewById(R.id.bottomRight_icon);
-        mIcon2TouchDelegate = new TransformingTouchDelegate(mIconView2);
+        ViewStub iconViewStub2 = findViewById(R.id.bottomRight_icon);
+        if (enableOverviewIconMenu()) {
+            iconViewStub2.setLayoutResource(R.layout.icon_app_chip_view);
+        } else {
+            iconViewStub2.setLayoutResource(R.layout.icon_view);
+        }
+        mIconView2 = (TaskViewIcon) iconViewStub2.inflate();
+        mIcon2TouchDelegate = new TransformingTouchDelegate(mIconView2.asView());
     }
 
     public void bind(Task primary, Task secondary, RecentsOrientedState orientedState,
@@ -160,6 +169,7 @@
                 mIconLoadRequest2 = iconCache.updateIconInBackground(mSecondaryTask,
                         (task) -> {
                             setIcon(mIconView2, task.icon);
+                            setText(mIconView2, TaskUtils.getTitle(getContext(), task));
                             mDigitalWellBeingToast2.initialize(mSecondaryTask);
                             mDigitalWellBeingToast2.setSplitConfiguration(mSplitBoundsConfig);
                             mDigitalWellBeingToast.setSplitConfiguration(mSplitBoundsConfig);
@@ -174,6 +184,7 @@
             }
             if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
                 setIcon(mIconView2, null);
+                setText(mIconView2, null);
             }
         }
     }
@@ -305,7 +316,7 @@
         }
 
         // Check which of the two apps was selected
-        if (isCoordInView(mIconView2, mLastTouchDownPosition)
+        if (isCoordInView(mIconView2.asView(), mLastTouchDownPosition)
                 || isCoordInView(mSnapshotView2, mLastTouchDownPosition)) {
             return 1;
         }
@@ -371,10 +382,7 @@
         super.setOrientationState(orientationState);
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
         boolean isGridTask = deviceProfile.isTablet && !isFocusedTask();
-        int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
-                : deviceProfile.overviewTaskIconDrawableSizePx;
-        mIconView2.setDrawableSize(iconDrawableSize, iconDrawableSize);
-        mIconView2.setRotation(getPagedOrientationHandler().getDegreesRotated());
+        mIconView2.setIconOrientation(orientationState, isGridTask);
         updateIconPlacement();
         updateSecondaryDwbPlacement();
     }
@@ -388,7 +396,7 @@
         int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
         boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
 
-        getPagedOrientationHandler().setSplitIconParams(mIconView, mIconView2,
+        getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
                 taskIconHeight, mSnapshotView.getMeasuredWidth(), mSnapshotView.getMeasuredHeight(),
                 getMeasuredHeight(), getMeasuredWidth(), isRtl, deviceProfile,
                 mSplitBoundsConfig);
diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.java b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
new file mode 100644
index 0000000..960a09e
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2023 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.quickstep.views;
+
+import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+import com.android.launcher3.touch.LandscapePagedViewHandler;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.touch.SeascapePagedViewHandler;
+import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.util.RecentsOrientedState;
+
+/**
+ * An icon app menu view which can be used in place of an IconView in overview TaskViews.
+ */
+public class IconAppChipView extends FrameLayout implements TaskViewIcon {
+
+    private static final int MENU_BACKGROUND_REVEAL_DURATION = 417;
+    private static final int MENU_BACKGROUND_HIDE_DURATION = 333;
+
+    private IconView mIconView;
+    private TextView mIconTextView;
+    private ImageView mIconArrowView;
+    private ImageView mIconViewBackground;
+
+    private int mMaxIconBackgroundWidth;
+    private int mMinIconBackgroundWidth;
+    private int mMaxIconBackgroundHeight;
+    private int mMinIconBackgroundHeight;
+    private int mIconTextMinWidth;
+    private int mIconTextMaxWidth;
+    private int mInnerMargin;
+    private int mIconArrowSize;
+    private int mIconMenuMarginStart;
+    private int mArrowMaxTranslationX;
+
+    public IconAppChipView(Context context) {
+        this(context, null);
+    }
+
+    public IconAppChipView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public IconAppChipView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public IconAppChipView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        mMaxIconBackgroundWidth = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_max_width);
+        mMinIconBackgroundWidth = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_min_width);
+        mMaxIconBackgroundHeight = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_max_height);
+        mMinIconBackgroundHeight = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_min_height);
+        mIconTextMaxWidth = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_text_max_width);
+        mInnerMargin = (int) getResources().getDimension(
+                R.dimen.task_thumbnail_icon_menu_arrow_margin);
+        mIconTextMinWidth = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_text_width) + (2 * mInnerMargin);
+        int taskIconHeight = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_drawable_touch_size);
+        int arrowWidth = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_arrow_size);
+        mIconArrowSize = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_arrow_drawable_size);
+        mIconMenuMarginStart = getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_margin);
+        mArrowMaxTranslationX =
+                mMaxIconBackgroundWidth - taskIconHeight - mIconTextMaxWidth + arrowWidth;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mIconView = findViewById(R.id.icon_view);
+        mIconTextView = findViewById(R.id.icon_text);
+        mIconArrowView = findViewById(R.id.icon_arrow);
+        mIconViewBackground = findViewById(R.id.icon_view_background);
+    }
+
+    protected IconView getIconView() {
+        return mIconView;
+    }
+
+    @Override
+    public void setText(CharSequence text) {
+        if (mIconTextView != null) {
+            mIconTextView.setText(text);
+        }
+    }
+
+    @Override
+    public Drawable getDrawable() {
+        return mIconView == null ? null : mIconView.getDrawable();
+    }
+
+    @Override
+    public void setDrawable(Drawable icon) {
+        if (mIconView != null) {
+            mIconView.setDrawable(icon);
+        }
+    }
+
+    @Override
+    public void setDrawableSize(int iconWidth, int iconHeight) {
+        if (mIconView != null) {
+            mIconView.setDrawableSize(iconWidth, iconHeight);
+        }
+    }
+
+    @Override
+    public void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask) {
+
+        PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
+        boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        DeviceProfile deviceProfile =
+                ActivityContext.lookupContext(getContext()).getDeviceProfile();
+
+        int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+        int taskIconSize = deviceProfile.overviewTaskIconSizePx;
+        int taskMargin = deviceProfile.overviewTaskMarginPx;
+
+        LayoutParams iconMenuParams = (LayoutParams) getLayoutParams();
+        orientationHandler.setTaskIconMenuParams(iconMenuParams, mIconMenuMarginStart,
+                thumbnailTopMargin);
+        iconMenuParams.width = mMinIconBackgroundWidth;
+        iconMenuParams.height = taskIconSize;
+        if (orientationHandler instanceof SeascapePagedViewHandler) {
+            // Use half menu height to place the pivot within the X/Y center of icon in the menu.
+            setPivotX(getHeight() / 2f);
+            setPivotY(getHeight() / 2f - mIconMenuMarginStart);
+        } else if (orientationHandler instanceof LandscapePagedViewHandler) {
+            setPivotX(getWidth());
+            setPivotY(0);
+        }
+        // Pivot not updated for PortraitPagedViewHandler case, as it has 0 rotation.
+
+        setTranslationY(0);
+        setRotation(orientationHandler.getDegreesRotated());
+
+        LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
+        orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconSize,
+                thumbnailTopMargin, isRtl);
+        iconParams.width = iconParams.height = taskIconSize;
+        iconParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
+        mIconView.setLayoutParams(iconParams);
+
+        int iconDrawableSize = enableOverviewIconMenu()
+                ? deviceProfile.overviewTaskIconAppChipMenuDrawableSizePx
+                : isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
+                        : deviceProfile.overviewTaskIconDrawableSizePx;
+        mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
+
+        LayoutParams iconTextParams = (LayoutParams) mIconTextView.getLayoutParams();
+        orientationHandler.setTaskIconParams(iconTextParams, 0, taskIconSize,
+                thumbnailTopMargin, isRtl);
+        iconTextParams.width = mIconTextMaxWidth;
+        iconTextParams.height = taskIconSize;
+        iconTextParams.setMarginStart(taskIconSize);
+        iconTextParams.topMargin = (getHeight() - mIconTextView.getHeight()) / 2;
+        iconTextParams.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
+        mIconTextView.setLayoutParams(iconTextParams);
+        mIconTextView.setRevealClip(true, 0, taskIconSize / 2f, mIconTextMinWidth);
+
+        LayoutParams iconArrowParams = (LayoutParams) mIconArrowView.getLayoutParams();
+        iconArrowParams.gravity = Gravity.CENTER_VERTICAL | Gravity.END;
+        iconArrowParams.setMarginStart(taskIconSize + mIconTextMinWidth);
+        iconArrowParams.setMarginEnd(mInnerMargin);
+        mIconArrowView.setLayoutParams(iconArrowParams);
+        mIconArrowView.getDrawable().setBounds(0, 0, mIconArrowSize, mIconArrowSize);
+
+        LayoutParams backgroundParams = (LayoutParams) mIconViewBackground.getLayoutParams();
+        backgroundParams.width = mMinIconBackgroundWidth;
+        backgroundParams.height = taskIconSize;
+        mIconViewBackground.setPivotX(
+                isRtl ? mMinIconBackgroundWidth - (taskIconSize / 2f - mInnerMargin)
+                        : taskIconSize / 2f - mInnerMargin);
+        mIconViewBackground.setPivotY(taskIconSize / 2f);
+
+        requestLayout();
+    }
+
+    @Override
+    public void setIconColorTint(int color, float amount) {
+        if (mIconView != null) {
+            mIconView.setIconColorTint(color, amount);
+        }
+    }
+
+    @Override
+    public int getDrawableWidth() {
+        return mIconView == null ? 0 : mIconView.getDrawableWidth();
+    }
+
+    @Override
+    public int getDrawableHeight() {
+        return mIconView == null ? 0 : mIconView.getDrawableHeight();
+    }
+
+    protected void revealAnim(boolean isRevealing) {
+        if (isRevealing) {
+            ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).start();
+            AnimatorSet anim = new AnimatorSet();
+            anim.playTogether(
+                    ViewAnimationUtils.createCircularReveal(mIconTextView, 0,
+                            mIconTextView.getHeight() / 2, mIconTextMinWidth, mIconTextMaxWidth),
+                    ObjectAnimator.ofFloat(mIconViewBackground, SCALE_X,
+                            mMaxIconBackgroundWidth / (float) mMinIconBackgroundWidth),
+                    ObjectAnimator.ofFloat(mIconViewBackground, SCALE_Y,
+                            mMaxIconBackgroundHeight / (float) mMinIconBackgroundHeight),
+                    ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X,
+                            isLayoutRtl() ? -mArrowMaxTranslationX : mArrowMaxTranslationX));
+            anim.setDuration(MENU_BACKGROUND_REVEAL_DURATION);
+            anim.setInterpolator(EMPHASIZED);
+            anim.start();
+        } else {
+            ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reverse();
+            AnimatorSet anim = new AnimatorSet();
+            Animator textRevealAnim = ViewAnimationUtils.createCircularReveal(mIconTextView, 0,
+                    mIconTextView.getHeight() / 2, mIconTextMaxWidth, mIconTextMinWidth);
+            textRevealAnim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    // createCircularReveal removes clip on finish, restore it here to clip text.
+                    mIconTextView.setRevealClip(true, 0, mIconTextView.getHeight() / 2f,
+                            mIconTextMinWidth);
+                }
+            });
+            anim.playTogether(
+                    textRevealAnim,
+                    ObjectAnimator.ofFloat(mIconViewBackground, SCALE_X, 1),
+                    ObjectAnimator.ofFloat(mIconViewBackground, SCALE_Y, 1),
+                    ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, 0));
+            anim.setDuration(MENU_BACKGROUND_HIDE_DURATION);
+            anim.setInterpolator(EMPHASIZED);
+            anim.start();
+        }
+    }
+
+    @Override
+    public View asView() {
+        return this;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index 5895c05..222f9ca 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep.views;
 
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
+
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -22,16 +24,21 @@
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
+import android.widget.FrameLayout;
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.util.RecentsOrientedState;
 
 /**
  * A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
  * when the drawable changes.
  */
-public class IconView extends View {
+public class IconView extends View implements TaskViewIcon {
 
     @Nullable
     private Drawable mDrawable;
@@ -52,6 +59,7 @@
     /**
      * Sets a {@link Drawable} to be displayed.
      */
+    @Override
     public void setDrawable(@Nullable Drawable d) {
         if (mDrawable != null) {
             mDrawable.setCallback(null);
@@ -67,6 +75,7 @@
     /**
      * Sets the size of the icon drawable.
      */
+    @Override
     public void setDrawableSize(int iconWidth, int iconHeight) {
         mDrawableWidth = iconWidth;
         mDrawableHeight = iconHeight;
@@ -82,15 +91,18 @@
         mDrawable.setBounds(drawableRect);
     }
 
+    @Override
     @Nullable
     public Drawable getDrawable() {
         return mDrawable;
     }
 
+    @Override
     public int getDrawableWidth() {
         return mDrawableWidth;
     }
 
+    @Override
     public int getDrawableHeight() {
         return mDrawableHeight;
     }
@@ -147,9 +159,41 @@
      * @param color to blend in.
      * @param amount [0,1] 0 no tint, 1 full tint
      */
+    @Override
     public void setIconColorTint(int color, float amount) {
         if (mDrawable != null) {
             mDrawable.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
         }
     }
+
+    @Override
+    public void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask) {
+        PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
+        boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        DeviceProfile deviceProfile =
+                ActivityContext.lookupContext(getContext()).getDeviceProfile();
+
+        FrameLayout.LayoutParams iconParams = (FrameLayout.LayoutParams) getLayoutParams();
+
+        int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+        int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
+        int taskMargin = deviceProfile.overviewTaskMarginPx;
+
+        orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconHeight,
+                thumbnailTopMargin, isRtl);
+        iconParams.width = iconParams.height = taskIconHeight;
+        setLayoutParams(iconParams);
+
+        setRotation(orientationHandler.getDegreesRotated());
+        int iconDrawableSize = enableOverviewIconMenu()
+                ? deviceProfile.overviewTaskIconAppChipMenuDrawableSizePx
+                : isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
+                        : deviceProfile.overviewTaskIconDrawableSizePx;
+        setDrawableSize(iconDrawableSize, iconDrawableSize);
+    }
+
+    @Override
+    public View asView() {
+        return this;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index b4d24e5..62c0bef 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -16,6 +16,8 @@
 
 package com.android.quickstep.views;
 
+import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
 import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
 
 import android.animation.Animator;
@@ -24,6 +26,7 @@
 import android.content.Context;
 import android.graphics.Outline;
 import android.graphics.Rect;
+import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.RectShape;
 import android.util.AttributeSet;
@@ -58,16 +61,19 @@
 
     private static final Rect sTempRect = new Rect();
 
-    private static final int REVEAL_OPEN_DURATION = 150;
-    private static final int REVEAL_CLOSE_DURATION = 100;
+    private static final int REVEAL_OPEN_DURATION = enableOverviewIconMenu() ? 417 : 150;
+    private static final int REVEAL_CLOSE_DURATION = enableOverviewIconMenu() ? 333 : 100;
 
     private BaseDraggingActivity mActivity;
     private TextView mTaskName;
     @Nullable
     private AnimatorSet mOpenCloseAnimator;
+    @Nullable private Runnable mOnClosingStartCallback;
     private TaskView mTaskView;
     private TaskIdAttributeContainer mTaskContainer;
     private LinearLayout mOptionLayout;
+    private float mMenuTranslationYBeforeOpen;
+    private float mIconViewTranslationYBeforeOpen;
 
     public TaskMenuView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -137,14 +143,20 @@
         }
     }
 
-    public static boolean showForTask(TaskIdAttributeContainer taskContainer) {
+    public static boolean showForTask(TaskIdAttributeContainer taskContainer,
+            @Nullable Runnable onClosingStartCallback) {
         BaseDraggingActivity activity = BaseDraggingActivity.fromContext(
                 taskContainer.getTaskView().getContext());
         final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
                         R.layout.task_menu, activity.getDragLayer(), false);
+        taskMenuView.setOnClosingStartCallback(onClosingStartCallback);
         return taskMenuView.populateAndShowForTask(taskContainer);
     }
 
+    public static boolean showForTask(TaskIdAttributeContainer taskContainer) {
+        return showForTask(taskContainer, null);
+    }
+
     private boolean populateAndShowForTask(TaskIdAttributeContainer taskContainer) {
         if (isAttachedToWindow()) {
             return false;
@@ -171,8 +183,12 @@
     }
 
     private void addMenuOptions(TaskIdAttributeContainer taskContainer) {
-        mTaskName.setText(TaskUtils.getTitle(getContext(), taskContainer.getTask()));
-        mTaskName.setOnClickListener(v -> close(true));
+        if (enableOverviewIconMenu()) {
+            removeView(mTaskName);
+        } else {
+            mTaskName.setText(TaskUtils.getTitle(getContext(), taskContainer.getTask()));
+            mTaskName.setOnClickListener(v -> close(true));
+        }
         TaskOverlayFactory.getEnabledShortcuts(mTaskView, taskContainer)
                 .forEach(this::addMenuOption);
     }
@@ -180,6 +196,9 @@
     private void addMenuOption(SystemShortcut menuOption) {
         LinearLayout menuOptionView = (LinearLayout) mActivity.getLayoutInflater().inflate(
                 R.layout.task_view_menu_option, this, false);
+        if (enableOverviewIconMenu()) {
+            ((GradientDrawable) menuOptionView.getBackground()).setCornerRadius(0);
+        }
         menuOption.setIconAndLabelFor(
                 menuOptionView.findViewById(R.id.icon), menuOptionView.findViewById(R.id.text));
         LayoutParams lp = (LayoutParams) menuOptionView.getLayoutParams();
@@ -198,8 +217,9 @@
 
         // Get Position
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-        mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskContainer.getThumbnailView(),
-                sTempRect);
+        mActivity.getDragLayer().getDescendantRectRelativeToSelf(
+                enableOverviewIconMenu() ? taskContainer.getIconView().asView()
+                        : taskContainer.getThumbnailView(), sTempRect);
         Rect insets = mActivity.getDragLayer().getInsets();
         BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
         int padding = getResources()
@@ -217,12 +237,17 @@
         ShapeDrawable divider = new ShapeDrawable(new RectShape());
         divider.getPaint().setColor(getResources().getColor(android.R.color.transparent));
         int dividerSpacing = (int) getResources().getDimension(R.dimen.task_menu_spacing);
-        mOptionLayout.setShowDividers(SHOW_DIVIDER_MIDDLE);
+        mOptionLayout.setShowDividers(
+                enableOverviewIconMenu() ? SHOW_DIVIDER_NONE : SHOW_DIVIDER_MIDDLE);
 
         orientationHandler.setTaskOptionsMenuLayoutOrientation(
                 deviceProfile, mOptionLayout, dividerSpacing, divider);
-        float thumbnailAlignedX = sTempRect.left - insets.left;
-        float thumbnailAlignedY = sTempRect.top - insets.top;
+        float thumbnailAlignedX = sTempRect.left - insets.left + (enableOverviewIconMenu()
+                ? -getResources().getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_touch_max_margin) : 0);
+        float thumbnailAlignedY = sTempRect.top - insets.top + (enableOverviewIconMenu()
+                ? getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_max_height)
+                - 2 * dividerSpacing : 0);
         // Changing pivot to make computations easier
         // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
         // which would render the X and Y position set here incorrect
@@ -231,15 +256,22 @@
         setRotation(orientationHandler.getDegreesRotated());
 
         // Margin that insets the menuView inside the taskView
-        float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
+        float taskInsetMargin =
+                enableOverviewIconMenu() ? getResources().getDimension(
+                        R.dimen.task_thumbnail_icon_menu_margin) : getResources().getDimension(
+                        R.dimen.task_card_margin);
         setTranslationX(orientationHandler.getTaskMenuX(thumbnailAlignedX,
-                mTaskContainer.getThumbnailView(), deviceProfile, taskInsetMargin));
+                mTaskContainer.getThumbnailView(), deviceProfile, taskInsetMargin,
+                mTaskContainer.getIconView().asView()));
         setTranslationY(orientationHandler.getTaskMenuY(
                 thumbnailAlignedY, mTaskContainer.getThumbnailView(),
-                mTaskContainer.getStagePosition(), this, taskInsetMargin));
+                mTaskContainer.getStagePosition(), this, taskInsetMargin,
+                mTaskContainer.getIconView().asView()));
     }
 
     private void animateOpen() {
+        mMenuTranslationYBeforeOpen = getTranslationY();
+        mIconViewTranslationYBeforeOpen = mTaskContainer.getIconView().asView().getTranslationY();
         animateOpenOrClosed(false);
         mIsOpen = true;
     }
@@ -256,7 +288,29 @@
 
         final Animator revealAnimator = createOpenCloseOutlineProvider()
                 .createRevealAnimator(this, closing);
-        revealAnimator.setInterpolator(Interpolators.DECELERATE);
+        revealAnimator.setInterpolator(enableOverviewIconMenu() ? Interpolators.EMPHASIZED
+                : Interpolators.DECELERATE);
+
+        if (enableOverviewIconMenu()
+                && ((RecentsView) mActivity.getOverviewPanel()).isOnGridBottomRow(mTaskView)) {
+            float taskBottom = mTaskView.getHeight() + mTaskView.getPersistentTranslationY();
+            float menuBottom = getHeight() + mMenuTranslationYBeforeOpen;
+            float additionalTranslationY = Math.max(menuBottom - taskBottom, 0);
+
+            ObjectAnimator translationYAnim = ObjectAnimator.ofFloat(this, TRANSLATION_Y,
+                    closing ? mMenuTranslationYBeforeOpen
+                            : mMenuTranslationYBeforeOpen - additionalTranslationY);
+            translationYAnim.setInterpolator(EMPHASIZED);
+
+            ObjectAnimator menuTranslationYAnim = ObjectAnimator.ofFloat(
+                    mTaskContainer.getIconView().asView(), TRANSLATION_Y,
+                    closing ? mIconViewTranslationYBeforeOpen
+                            : mIconViewTranslationYBeforeOpen - additionalTranslationY);
+            menuTranslationYAnim.setInterpolator(EMPHASIZED);
+
+            mOpenCloseAnimator.playTogether(translationYAnim, menuTranslationYAnim);
+        }
+
         mOpenCloseAnimator.playTogether(revealAnimator,
                 ObjectAnimator.ofFloat(
                         mTaskContainer.getThumbnailView(), DIM_ALPHA,
@@ -266,6 +320,9 @@
             @Override
             public void onAnimationStart(Animator animation) {
                 setVisibility(VISIBLE);
+                if (closing && mOnClosingStartCallback != null) {
+                    mOnClosingStartCallback.run();
+                }
             }
 
             @Override
@@ -286,9 +343,16 @@
 
     private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
         float radius = TaskCornerRadius.get(mContext);
-        Rect fromRect = new Rect(0, 0, getWidth(), 0);
+        Rect fromRect = new Rect(
+                enableOverviewIconMenu() && isLayoutRtl() ? getWidth() : 0,
+                0,
+                enableOverviewIconMenu() && !isLayoutRtl() ? 0 : getWidth(),
+                0);
         Rect toRect = new Rect(0, 0, getWidth(), getHeight());
         return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
     }
 
+    private void setOnClosingStartCallback(Runnable onClosingStartCallback) {
+        mOnClosingStartCallback = onClosingStartCallback;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index b373911..12b8b6f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -106,7 +106,7 @@
     override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0
 
     override fun getTargetObjectLocation(outPos: Rect?) {
-        popupContainer.getDescendantRectRelativeToSelf(taskContainer.iconView, outPos)
+        popupContainer.getDescendantRectRelativeToSelf(taskContainer.iconView.asView(), outPos)
     }
 
     override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 50b38ea..6ae1973 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -25,6 +25,7 @@
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -63,6 +64,7 @@
 import android.view.TouchDelegate;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
@@ -352,7 +354,7 @@
     @Nullable
     protected Task mTask;
     protected TaskThumbnailView mSnapshotView;
-    protected IconView mIconView;
+    protected TaskViewIcon mIconView;
     protected final DigitalWellBeingToast mDigitalWellBeingToast;
     protected float mFullscreenProgress;
     private float mGridProgress;
@@ -519,8 +521,14 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mSnapshotView = findViewById(R.id.snapshot);
-        mIconView = findViewById(R.id.icon);
-        mIconTouchDelegate = new TransformingTouchDelegate(mIconView);
+        ViewStub iconViewStub = findViewById(R.id.icon);
+        if (enableOverviewIconMenu()) {
+            iconViewStub.setLayoutResource(R.layout.icon_app_chip_view);
+        } else {
+            iconViewStub.setLayoutResource(R.layout.icon_view);
+        }
+        mIconView = (TaskViewIcon) iconViewStub.inflate();
+        mIconTouchDelegate = new TransformingTouchDelegate(mIconView.asView());
     }
 
     @Override
@@ -563,14 +571,14 @@
 
     @Override
     public void draw(Canvas canvas) {
-        super.draw(canvas);
+        // Draw border first so any child views outside of the thumbnail bounds are drawn above it.
         if (mFocusBorderAnimator != null) {
             mFocusBorderAnimator.drawBorder(canvas);
         }
-
         if (mHoverBorderAnimator != null) {
             mHoverBorderAnimator.drawBorder(canvas);
         }
+        super.draw(canvas);
     }
 
     /**
@@ -587,17 +595,22 @@
         return false;
     }
 
-    protected void computeAndSetIconTouchDelegate(IconView iconView, float[] tempCenterCoords,
+    protected void computeAndSetIconTouchDelegate(TaskViewIcon view, float[] tempCenterCoords,
             TransformingTouchDelegate transformingTouchDelegate) {
-        float iconHalfSize = iconView.getWidth() / 2f;
-        tempCenterCoords[0] = tempCenterCoords[1] = iconHalfSize;
-        getDescendantCoordRelativeToAncestor(iconView, mActivity.getDragLayer(), tempCenterCoords,
-                false);
+        if (view == null) {
+            return;
+        }
+        float viewHalfWidth = view.getWidth() / 2f;
+        float viewHalfHeight = view.getHeight() / 2f;
+        tempCenterCoords[0] = viewHalfWidth;
+        tempCenterCoords[1] = viewHalfHeight;
+        getDescendantCoordRelativeToAncestor(view.asView(), mActivity.getDragLayer(),
+                tempCenterCoords, false);
         transformingTouchDelegate.setBounds(
-                (int) (tempCenterCoords[0] - iconHalfSize),
-                (int) (tempCenterCoords[1] - iconHalfSize),
-                (int) (tempCenterCoords[0] + iconHalfSize),
-                (int) (tempCenterCoords[1] + iconHalfSize));
+                (int) (tempCenterCoords[0] - viewHalfWidth),
+                (int) (tempCenterCoords[1] - viewHalfHeight),
+                (int) (tempCenterCoords[0] + viewHalfWidth),
+                (int) (tempCenterCoords[1] + viewHalfHeight));
     }
 
     /**
@@ -629,8 +642,8 @@
         cancelPendingLoadTasks();
         mTask = task;
         mTaskIdContainer[0] = mTask.key.id;
-        mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task, mSnapshotView,
-                mIconView, STAGE_POSITION_UNDEFINED);
+        mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task, mSnapshotView, mIconView,
+                STAGE_POSITION_UNDEFINED);
         mSnapshotView.bind(task);
         setOrientationState(orientedState);
     }
@@ -745,7 +758,7 @@
         return new TaskThumbnailView[]{mSnapshotView};
     }
 
-    public IconView getIconView() {
+    public TaskViewIcon getIconView() {
         return mIconView;
     }
 
@@ -1075,6 +1088,7 @@
                 mIconLoadRequest = iconCache.updateIconInBackground(mTask,
                         (task) -> {
                             setIcon(mIconView, task.icon);
+                            setText(mIconView, TaskUtils.getTitle(getContext(), task));
                             mDigitalWellBeingToast.initialize(task);
                         });
             }
@@ -1090,6 +1104,7 @@
             }
             if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
                 setIcon(mIconView, null);
+                setText(mIconView, null);
             }
         }
     }
@@ -1109,7 +1124,7 @@
         }
     }
 
-    private boolean showTaskMenu(IconView iconView) {
+    private boolean showTaskMenu(TaskViewIcon iconView) {
         if (!getRecentsView().canLaunchFullscreenTask()) {
             // Don't show menu when selecting second split screen app
             return true;
@@ -1126,11 +1141,16 @@
         }
     }
 
-    protected boolean showTaskMenuWithContainer(IconView iconView) {
+    protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
         TaskIdAttributeContainer menuContainer =
                 mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1];
         DeviceProfile dp = mActivity.getDeviceProfile();
-        if (dp.isTablet) {
+        if (enableOverviewIconMenu() && iconView instanceof IconAppChipView) {
+            ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ true);
+            return TaskMenuView.showForTask(menuContainer, () -> {
+                ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false);
+            });
+        } else if (dp.isTablet) {
             int alignedOptionIndex = 0;
             if (getRecentsView().isOnGridBottomRow(menuContainer.getTaskView()) && dp.isLandscape) {
                 if (FeatureFlags.enableGridOnlyOverview()) {
@@ -1142,13 +1162,14 @@
                     alignedOptionIndex = 1;
                 }
             }
-            return TaskMenuViewWithArrow.Companion.showForTask(menuContainer, alignedOptionIndex);
+            return TaskMenuViewWithArrow.Companion.showForTask(menuContainer,
+                    alignedOptionIndex);
         } else {
             return TaskMenuView.showForTask(menuContainer);
         }
     }
 
-    protected void setIcon(IconView iconView, @Nullable Drawable icon) {
+    protected void setIcon(TaskViewIcon iconView, @Nullable Drawable icon) {
         if (icon != null) {
             iconView.setDrawable(icon);
             iconView.setOnClickListener(v -> {
@@ -1168,32 +1189,13 @@
         }
     }
 
-    public void setOrientationState(RecentsOrientedState orientationState) {
-        setIconOrientation(orientationState);
-        setThumbnailOrientation(orientationState);
+    protected void setText(TaskViewIcon iconView, CharSequence text) {
+        iconView.setText(text);
     }
 
-    protected void setIconOrientation(RecentsOrientedState orientationState) {
-        PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
-        boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-
-        boolean isGridTask = isGridTask();
-        LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
-
-        int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
-        int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
-        int taskMargin = deviceProfile.overviewTaskMarginPx;
-
-        orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconHeight,
-                thumbnailTopMargin, isRtl);
-        iconParams.width = iconParams.height = taskIconHeight;
-        mIconView.setLayoutParams(iconParams);
-
-        mIconView.setRotation(orientationHandler.getDegreesRotated());
-        int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
-                : deviceProfile.overviewTaskIconDrawableSizePx;
-        mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
+    public void setOrientationState(RecentsOrientedState orientationState) {
+        mIconView.setIconOrientation(orientationState, isGridTask());
+        setThumbnailOrientation(orientationState);
     }
 
     protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
@@ -1898,14 +1900,14 @@
     public class TaskIdAttributeContainer {
         private final TaskThumbnailView mThumbnailView;
         private final Task mTask;
-        private final IconView mIconView;
+        private final TaskViewIcon mIconView;
         /** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */
         private @SplitConfigurationOptions.StagePosition int mStagePosition;
         @IdRes
         private final int mA11yNodeId;
 
         public TaskIdAttributeContainer(Task task, TaskThumbnailView thumbnailView,
-                IconView iconView, int stagePosition) {
+                TaskViewIcon iconView, int stagePosition) {
             this.mTask = task;
             this.mThumbnailView = thumbnailView;
             this.mIconView = iconView;
@@ -1930,7 +1932,7 @@
             return TaskView.this;
         }
 
-        public IconView getIconView() {
+        public TaskViewIcon getIconView() {
             return mIconView;
         }
 
diff --git a/quickstep/src/com/android/quickstep/views/TaskViewIcon.java b/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
new file mode 100644
index 0000000..b4f21be
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 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.quickstep.views;
+
+import android.annotation.Nullable;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.quickstep.util.RecentsOrientedState;
+
+/**
+ * Interface defining an object which can be used as a TaskView's icon.
+ */
+public interface TaskViewIcon {
+
+    /**
+     * Returns the width of this icon view.
+     */
+    int getWidth();
+
+    /**
+     * Returns the height of this icon view.
+     */
+    int getHeight();
+
+    /**
+     * Sets the opacity of the view.
+     */
+    void setAlpha(float alpha);
+
+    /**
+     * Returns this icon view's drawable.
+     */
+    @Nullable Drawable getDrawable();
+
+    /**
+     * Sets a {@link Drawable} to be displayed.
+     */
+    void setDrawable(@Nullable Drawable icon);
+
+    /**
+     * Register a callback to be invoked when this view is clicked.
+     */
+    void setOnClickListener(@Nullable View.OnClickListener l);
+
+    /**
+     * Register a callback to be invoked when this view is clicked and held.
+     */
+    void setOnLongClickListener(@Nullable View.OnLongClickListener l);
+
+    /**
+     * Returns the LayoutParams associated with this view.
+     */
+    ViewGroup.LayoutParams getLayoutParams();
+
+    /**
+     * Sets the layout parameters associated with this view.
+     */
+    void setLayoutParams(ViewGroup.LayoutParams params);
+
+    /**
+     * Sets the degrees that the view is rotated around the pivot point.
+     */
+    void setRotation(float rotation);
+
+    /**
+     * Sets the size of the icon drawable.
+     */
+    void setDrawableSize(int iconWidth, int iconHeight);
+
+    /**
+     * Sets the orientation of this icon view based on the provided orientationState.
+     */
+    void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask);
+
+    /**
+     * Sets the visibility state of this view.
+     */
+    void setVisibility(int visibility);
+
+    /**
+     * Sets the tint color of the icon, useful for scrimming or dimming.
+     *
+     * @param color to blend in.
+     * @param amount [0,1] 0 no tint, 1 full tint
+     */
+    void setIconColorTint(int color, float amount);
+
+    /**
+     * Gets the opacity of the view.
+     */
+    float getAlpha();
+
+    /**
+     * Returns the width of this icon view's drawable.
+     */
+    int getDrawableWidth();
+
+    /**
+     * Returns the height of this icon view's drawable.
+     */
+    int getDrawableHeight();
+
+    /**
+     * Directly calls any attached OnClickListener.
+     */
+    boolean callOnClick();
+
+    /**
+     * Calls this view's OnLongClickListener.
+     */
+    boolean performLongClick();
+
+    /**
+     * Sets the text for this icon view if any text view is associated.
+     */
+    default void setText(CharSequence text) {}
+
+    /**
+     * Returns this icon view cast as a View.
+     */
+    View asView();
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 211a13c..45eeba9 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -17,6 +17,7 @@
 package com.android.quickstep;
 
 import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ICON_MENU;
 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
 
@@ -208,6 +209,23 @@
                 isInLaunchedApp(launcher)));
     }
 
+
+    @Test
+    public void testOverviewActionsMenu_iconAppChipMenu() throws Exception {
+        try (AutoCloseable c = TestUtil.overrideFlag(ENABLE_OVERVIEW_ICON_MENU, true)) {
+            startTestAppsWithCheck();
+
+            OverviewTaskMenu menu =
+                    mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu();
+
+            assertNotNull("Tapping App info menu item returned null", menu.tapAppInfoMenuItem());
+            executeOnLauncher(launcher -> assertTrue(
+                    "Launcher activity is the top activity; expecting another activity to be the "
+                            + "top",
+                    isInLaunchedApp(launcher)));
+        }
+    }
+
     private int getCurrentOverviewPage(Launcher launcher) {
         return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
     }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index cc56faf..ed152f2 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -16,6 +16,7 @@
 package com.android.quickstep;
 
 
+import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ICON_MENU;
 import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
 import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
@@ -30,8 +31,10 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.tapl.OverviewTaskMenu;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
@@ -139,6 +142,42 @@
                         .hasMenuItem("Save app pair"));
     }
 
+    @Test
+    public void testTapBothIconMenus() {
+        createAndLaunchASplitPair();
+
+        OverviewTaskMenu taskMenu =
+                mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu();
+        assertTrue("App info item not appearing in expanded task menu.",
+                taskMenu.hasMenuItem("App info"));
+        taskMenu.touchOutsideTaskMenuToDismiss();
+
+        OverviewTaskMenu splitMenu =
+                mLauncher.getOverview().getCurrentTask().tapSplitTaskMenu();
+        assertTrue("App info item not appearing in expanded split task's menu.",
+                splitMenu.hasMenuItem("App info"));
+        splitMenu.touchOutsideTaskMenuToDismiss();
+    }
+
+    @Test
+    public void testTapBothIconMenus_iconAppChipMenu() throws Exception {
+        try (AutoCloseable c = TestUtil.overrideFlag(ENABLE_OVERVIEW_ICON_MENU, true)) {
+            createAndLaunchASplitPair();
+
+            OverviewTaskMenu taskMenu =
+                    mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu();
+            assertTrue("App info item not appearing in expanded task menu.",
+                    taskMenu.hasMenuItem("App info"));
+            taskMenu.touchOutsideTaskMenuToDismiss();
+
+            OverviewTaskMenu splitMenu =
+                    mLauncher.getOverview().getCurrentTask().tapSplitTaskMenu();
+            assertTrue("App info item not appearing in expanded split task's menu.",
+                    splitMenu.hasMenuItem("App info"));
+            splitMenu.touchOutsideTaskMenuToDismiss();
+        }
+    }
+
     private void createAndLaunchASplitPair() {
         startTestActivity(2);
         startTestActivity(3);
diff --git a/res/drawable/icon_menu_arrow_background.xml b/res/drawable/icon_menu_arrow_background.xml
new file mode 100644
index 0000000..f24022e
--- /dev/null
+++ b/res/drawable/icon_menu_arrow_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2023 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:autoMirrored="true">
+    <gradient
+        android:type="linear"
+        android:angle="0"
+        android:startColor="#00000000"
+        android:centerX="0.25"
+        android:centerColor="?androidprv:attr/materialColorSurfaceContainer"
+        android:endColor="?androidprv:attr/materialColorSurfaceContainer" />
+    <corners android:radius="@dimen/dialogCornerRadius" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/icon_menu_background.xml b/res/drawable/icon_menu_background.xml
new file mode 100644
index 0000000..ec5f011
--- /dev/null
+++ b/res/drawable/icon_menu_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2023 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="rectangle">
+    <solid android:color="?androidprv:attr/materialColorSurfaceContainer" />
+    <corners android:radius="@dimen/dialogCornerRadius" />
+</shape>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 10f47cb..7661bd7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -399,6 +399,10 @@
     <dimen name="task_thumbnail_icon_size">0dp</dimen>
     <dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
     <dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
+    <dimen name="task_thumbnail_icon_menu_max_width">0dp</dimen>
+    <dimen name="task_thumbnail_icon_menu_drawable_size">0dp</dimen>
+    <dimen name="task_thumbnail_icon_menu_drawable_touch_size">0dp</dimen>
+    <dimen name="task_menu_vertical_padding">0dp</dimen>
     <dimen name="overview_task_margin">0dp</dimen>
     <dimen name="overview_actions_height">0dp</dimen>
     <dimen name="overview_actions_button_spacing">0dp</dimen>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index d8804a1..94eb7a3 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -24,6 +24,7 @@
 import static com.android.launcher3.Utilities.dpiFromPx;
 import static com.android.launcher3.Utilities.pxFromSp;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
 import static com.android.launcher3.icons.GraphicsUtils.getShapePath;
 import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
@@ -250,6 +251,7 @@
     public int overviewTaskIconSizePx;
     public int overviewTaskIconDrawableSizePx;
     public int overviewTaskIconDrawableSizeGridPx;
+    public int overviewTaskIconAppChipMenuDrawableSizePx;
     public int overviewTaskThumbnailTopMarginPx;
     public final int overviewActionsHeight;
     public final int overviewActionsTopMarginPx;
@@ -614,12 +616,17 @@
         desiredWorkspaceHorizontalMarginOriginalPx = desiredWorkspaceHorizontalMarginPx;
 
         overviewTaskMarginPx = res.getDimensionPixelSize(R.dimen.overview_task_margin);
-        overviewTaskIconSizePx = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
+        overviewTaskIconSizePx = enableOverviewIconMenu() ? res.getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_drawable_touch_size) : res.getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_size);
         overviewTaskIconDrawableSizePx =
                 res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size);
         overviewTaskIconDrawableSizeGridPx =
                 res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size_grid);
-        overviewTaskThumbnailTopMarginPx = overviewTaskIconSizePx + overviewTaskMarginPx;
+        overviewTaskIconAppChipMenuDrawableSizePx = res.getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_drawable_size);
+        overviewTaskThumbnailTopMarginPx =
+                enableOverviewIconMenu() ? 0 : overviewTaskIconSizePx + overviewTaskMarginPx;
         // Don't add margin with floating search bar to minimize risk of overlapping.
         overviewActionsTopMarginPx = FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() ? 0
                 : res.getDimensionPixelSize(R.dimen.overview_actions_top_margin);
@@ -2016,6 +2023,8 @@
                 overviewTaskIconDrawableSizePx));
         writer.println(prefix + pxToDpStr("overviewTaskIconDrawableSizeGridPx",
                 overviewTaskIconDrawableSizeGridPx));
+        writer.println(prefix + pxToDpStr("overviewTaskIconAppChipMenuDrawableSizePx",
+                overviewTaskIconAppChipMenuDrawableSizePx));
         writer.println(prefix + pxToDpStr("overviewTaskThumbnailTopMarginPx",
                 overviewTaskThumbnailTopMarginPx));
         writer.println(prefix + pxToDpStr("overviewActionsTopMarginPx",
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 9fb175d..a3c434a 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -327,6 +327,15 @@
         return ENABLE_GRID_ONLY_OVERVIEW.get() || Flags.enableGridOnlyOverview();
     }
 
+    // Aconfig migration complete for ENABLE_OVERVIEW_ICON_MENU.
+    @VisibleForTesting
+    public static final BooleanFlag ENABLE_OVERVIEW_ICON_MENU = getDebugFlag(257950105,
+            "ENABLE_OVERVIEW_ICON_MENU", TEAMFOOD,
+            "Enable updated overview icon and menu within task.");
+    public static boolean enableOverviewIconMenu() {
+        return ENABLE_OVERVIEW_ICON_MENU.get() || Flags.enableOverviewIconMenu();
+    }
+
     // Aconfig migration complete for ENABLE_CURSOR_HOVER_STATES.
     @VisibleForTesting
     public static final BooleanFlag ENABLE_CURSOR_HOVER_STATES = getDebugFlag(243191650,
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index c356da9..d434ad2 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -27,6 +27,7 @@
 
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
 import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -267,13 +268,19 @@
 
     @Override
     public float getTaskMenuX(float x, View thumbnailView,
-            DeviceProfile deviceProfile, float taskInsetMargin) {
+            DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
+        if (enableOverviewIconMenu()) {
+            return x - (taskInsetMargin / 2f);
+        }
         return thumbnailView.getMeasuredWidth() + x - taskInsetMargin;
     }
 
     @Override
     public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
-            View taskMenuView, float taskInsetMargin) {
+            View taskMenuView, float taskInsetMargin, View taskViewIcon) {
+        if (enableOverviewIconMenu()) {
+            return y - taskMenuView.getMeasuredHeight() - taskInsetMargin;
+        }
         BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
         int taskMenuWidth = lp.width;
         if (stagePosition == STAGE_POSITION_UNDEFINED) {
@@ -537,14 +544,25 @@
     }
 
     @Override
+    public void setTaskIconMenuParams(FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin,
+            int thumbnailTopMargin) {
+        iconMenuParams.gravity = END | TOP;
+        iconMenuParams.setMarginStart(0);
+        iconMenuParams.topMargin = iconMenuParams.width + iconMenuMargin;
+        iconMenuParams.bottomMargin = 0;
+        iconMenuParams.setMarginEnd(iconMenuMargin);
+    }
+
+    @Override
     public void setSplitIconParams(View primaryIconView, View secondaryIconView,
             int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
             int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
             DeviceProfile deviceProfile, SplitBounds splitConfig) {
         FrameLayout.LayoutParams primaryIconParams =
                 (FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
-        FrameLayout.LayoutParams secondaryIconParams =
-                new FrameLayout.LayoutParams(primaryIconParams);
+        FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu()
+                ? (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams()
+                : new FrameLayout.LayoutParams(primaryIconParams);
 
         // We calculate the "midpoint" of the thumbnail area, and place the icons there.
         // This is the place where the thumbnail area splits by default, in a near-50/50 split.
@@ -560,11 +578,17 @@
         int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
         int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
 
-        primaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
-        secondaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
+        primaryIconParams.gravity = enableOverviewIconMenu() ? TOP | (isRtl ? START : END)
+                : BOTTOM | (isRtl ? START : END);
+        secondaryIconParams.gravity = enableOverviewIconMenu() ? TOP | (isRtl ? START : END)
+                : BOTTOM | (isRtl ? START : END);
         primaryIconView.setTranslationX(0);
         secondaryIconView.setTranslationX(0);
-        if (splitConfig.initiatedFromSeascape) {
+        if (enableOverviewIconMenu()) {
+            int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
+                    splitConfig.visualDividerBounds.height());
+            secondaryIconView.setTranslationY(primarySnapshotHeight + dividerThickness);
+        } else if (splitConfig.initiatedFromSeascape) {
             // if the split was initiated from seascape,
             // the task on the right (secondary) is slightly larger
             primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 39ef129..0069d9b 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -173,6 +173,8 @@
     // Overview TaskMenuView methods
     void setTaskIconParams(FrameLayout.LayoutParams iconParams,
             int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
+    void setTaskIconMenuParams(FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin,
+            int thumbnailTopMargin);
     void setSplitIconParams(View primaryIconView, View secondaryIconView,
             int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
             int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
@@ -185,9 +187,9 @@
      * getTaskMenuWidth()), so we directly use that in the calculations.
      */
     float getTaskMenuX(float x, View thumbnailView, DeviceProfile deviceProfile,
-            float taskInsetMargin);
+            float taskInsetMargin, View taskViewIcon);
     float getTaskMenuY(float y, View thumbnailView, int stagePosition,
-            View taskMenuView, float taskInsetMargin);
+            View taskMenuView, float taskInsetMargin, View taskViewIcon);
     int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
             @StagePosition int stagePosition);
     /**
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index dc4621e..b3189b7 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -21,11 +21,13 @@
 import static android.view.Gravity.END;
 import static android.view.Gravity.START;
 import static android.view.Gravity.TOP;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
 import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -264,8 +266,11 @@
 
     @Override
     public float getTaskMenuX(float x, View thumbnailView,
-            DeviceProfile deviceProfile, float taskInsetMargin) {
-        if (deviceProfile.isLandscape) {
+            DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
+        if (enableOverviewIconMenu()) {
+            return x + (thumbnailView.getLayoutDirection() == LAYOUT_DIRECTION_RTL
+                    ? -(taskViewIcon.getWidth() / 2f) : 0);
+        } else if (deviceProfile.isLandscape) {
             return x + taskInsetMargin
                     + (thumbnailView.getMeasuredWidth() - thumbnailView.getMeasuredHeight()) / 2f;
         } else {
@@ -275,13 +280,22 @@
 
     @Override
     public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
-            View taskMenuView, float taskInsetMargin) {
+            View taskMenuView, float taskInsetMargin, View taskViewIcon) {
+        if (enableOverviewIconMenu()) {
+            return y;
+        }
         return y + taskInsetMargin;
     }
 
     @Override
     public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
             @StagePosition int stagePosition) {
+        if (enableOverviewIconMenu()) {
+            int padding = thumbnailView.getResources().getDimensionPixelSize(
+                    R.dimen.task_menu_vertical_padding);
+            return thumbnailView.getResources().getDimensionPixelSize(
+                    R.dimen.task_thumbnail_icon_menu_max_width) + (2 * padding);
+        }
         return deviceProfile.isLandscape && !deviceProfile.isTablet
                 ? thumbnailView.getMeasuredHeight()
                 : thumbnailView.getMeasuredWidth();
@@ -689,16 +703,53 @@
     }
 
     @Override
+    public void setTaskIconMenuParams(FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin,
+            int thumbnailTopMargin) {
+        iconMenuParams.gravity = TOP | START;
+        iconMenuParams.setMarginStart(iconMenuMargin);
+        iconMenuParams.topMargin = iconMenuMargin;
+        iconMenuParams.bottomMargin = 0;
+        iconMenuParams.setMarginEnd(0);
+    }
+
+    @Override
     public void setSplitIconParams(View primaryIconView, View secondaryIconView,
             int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
             int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
             DeviceProfile deviceProfile, SplitBounds splitConfig) {
         FrameLayout.LayoutParams primaryIconParams =
                 (FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
-        FrameLayout.LayoutParams secondaryIconParams =
-                new FrameLayout.LayoutParams(primaryIconParams);
+        FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu()
+                ? (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams()
+                : new FrameLayout.LayoutParams(primaryIconParams);
 
-        if (deviceProfile.isLandscape) {
+        if (enableOverviewIconMenu()) {
+            primaryIconParams.gravity = TOP | START;
+            secondaryIconParams.gravity = TOP | START;
+            secondaryIconParams.topMargin = primaryIconParams.topMargin;
+            secondaryIconParams.setMarginStart(primaryIconParams.getMarginStart());
+            if (deviceProfile.isLandscape) {
+                int fullscreenInsetThickness = deviceProfile.isSeascape()
+                        ? deviceProfile.getInsets().right
+                        : deviceProfile.getInsets().left;
+                int fullscreenMidpointFromBottom = ((deviceProfile.widthPx
+                        - fullscreenInsetThickness) / 2);
+                float midpointFromEndPct = (float) fullscreenMidpointFromBottom
+                        / deviceProfile.widthPx;
+                int bottomToMidpointOffset = (int) (groupedTaskViewWidth * midpointFromEndPct);
+                if (isRtl) {
+                    primaryIconView.setTranslationX(-bottomToMidpointOffset);
+                } else {
+                    secondaryIconView.setTranslationX(bottomToMidpointOffset);
+                }
+            } else {
+                secondaryIconView.setTranslationX(0);
+                int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
+                        splitConfig.visualDividerBounds.height());
+                secondaryIconView.setTranslationY(
+                        primarySnapshotHeight + (deviceProfile.isTablet ? 0 : dividerThickness));
+            }
+        } else if (deviceProfile.isLandscape) {
             // We calculate the "midpoint" of the thumbnail area, and place the icons there.
             // This is the place where the thumbnail area splits by default, in a near-50/50 split.
             // It is usually not exactly 50/50, due to insets/screen cutouts.
@@ -754,8 +805,10 @@
             secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
             secondaryIconView.setTranslationX(taskIconHeight / 2f);
         }
-        primaryIconView.setTranslationY(0);
-        secondaryIconView.setTranslationY(0);
+        if (!enableOverviewIconMenu()) {
+            primaryIconView.setTranslationY(0);
+            secondaryIconView.setTranslationY(0);
+        }
 
         primaryIconView.setLayoutParams(primaryIconParams);
         secondaryIconView.setLayoutParams(secondaryIconParams);
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index ec01231..dac7964 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -22,6 +22,7 @@
 import static android.view.Gravity.RIGHT;
 import static android.view.Gravity.START;
 
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
 import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
@@ -86,13 +87,19 @@
 
     @Override
     public float getTaskMenuX(float x, View thumbnailView,
-            DeviceProfile deviceProfile, float taskInsetMargin) {
+            DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
+        if (enableOverviewIconMenu()) {
+            return x + taskViewIcon.getHeight() + taskInsetMargin * 2;
+        }
         return x + taskInsetMargin;
     }
 
     @Override
     public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
-            View taskMenuView, float taskInsetMargin) {
+            View taskMenuView, float taskInsetMargin, View taskViewIcon) {
+        if (enableOverviewIconMenu()) {
+            return y + taskViewIcon.getWidth() - taskViewIcon.getHeight();
+        }
         BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
         int taskMenuWidth = lp.width;
         if (stagePosition == STAGE_POSITION_UNDEFINED) {
@@ -208,13 +215,24 @@
     public void setTaskIconParams(FrameLayout.LayoutParams iconParams,
             int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
         iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
-        iconParams.leftMargin = -taskIconHeight - taskIconMargin / 2;
+        iconParams.leftMargin =
+                enableOverviewIconMenu() ? 0 : -taskIconHeight - taskIconMargin / 2;
         iconParams.rightMargin = 0;
-        iconParams.topMargin = thumbnailTopMargin / 2;
+        iconParams.topMargin = enableOverviewIconMenu() ? 0 : thumbnailTopMargin / 2;
         iconParams.bottomMargin = 0;
     }
 
     @Override
+    public void setTaskIconMenuParams(FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin,
+            int thumbnailTopMargin) {
+        iconMenuParams.gravity = BOTTOM | START;
+        iconMenuParams.setMarginStart(0);
+        iconMenuParams.topMargin = 0;
+        iconMenuParams.bottomMargin = 0;
+        iconMenuParams.setMarginEnd(0);
+    }
+
+    @Override
     public void setSplitIconParams(View primaryIconView, View secondaryIconView,
             int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
             int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
@@ -245,7 +263,11 @@
         secondaryIconParams.gravity = BOTTOM | (isRtl ? END : START);
         primaryIconView.setTranslationX(0);
         secondaryIconView.setTranslationX(0);
-        if (splitConfig.initiatedFromSeascape) {
+        if (enableOverviewIconMenu()) {
+            int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
+                    splitConfig.visualDividerBounds.height());
+            secondaryIconView.setTranslationY(-primarySnapshotHeight - dividerThickness);
+        } else if (splitConfig.initiatedFromSeascape) {
             // if the split was initiated from seascape,
             // the task on the right (secondary) is slightly larger
             primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
index b8f4c0b..ec32680 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
index a512277..d69be3f 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
index a3a8dc5..7e92620 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
index 55066cb..a9bee2b 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
index 6e764c2..42b022b 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
index 7650082..53f8580 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
index 2b241a1..87189fa 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
index 6d38d27..0ade560 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
index 5799de7..d24457d 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
index b4956ff..38dc2c9 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
index 15afb61..5d23147 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
index 6cbed1f..5b53509 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
@@ -108,6 +108,7 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index f0c4fdb..2cdcf24 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -87,6 +87,7 @@
         MockitoAnnotations.initMocks(this);
         mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
         mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_CURSOR_HOVER_STATES);
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU);
         Utilities.enableRunningInTestHarnessForTests();
         mContext = new ActivityContextWrapper(getApplicationContext());
         mBubbleTextView = new BubbleTextView(mContext);
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 130bd3a..bbd7467 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -2202,6 +2202,8 @@
                     containerBounds.bottom,
                     getRealDisplaySize().y - getImeInsets().bottom);
             int y = (bottomBound - containerBounds.top) / 2;
+            // Do not tap in the status bar.
+            y = Math.max(y, getWindowInsets().top);
 
             final long downTime = SystemClock.uptimeMillis();
             final Point tapTarget = new Point(x, y);
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index e4cfc52..95a4802 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -168,7 +168,7 @@
         }
     }
 
-    /** Taps the task menu. */
+    /** Taps the task menu. Returns the task menu object. */
     @NonNull
     public OverviewTaskMenu tapMenu() {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
@@ -184,6 +184,22 @@
         }
     }
 
+    /** Taps the task menu of the split task. Returns the split task's menu object. */
+    @NonNull
+    public OverviewTaskMenu tapSplitTaskMenu() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to tap the split task's menu")) {
+            mLauncher.clickLauncherObject(
+                    mLauncher.waitForObjectInContainer(mTask.getParent(), "bottomRight_icon"));
+
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "tapped the split task's menu")) {
+                return new OverviewTaskMenu(mLauncher);
+            }
+        }
+    }
+
     boolean isTaskSplit() {
         return mLauncher.findObjectInContainer(mTask.getParent(), "bottomright_snapshot") != null;
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 859e504..25c73de 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -91,4 +91,11 @@
         return new OverviewTaskMenuItem(mLauncher,
                 mLauncher.waitForObjectInContainer(mMenu, By.text(menuItemName)));
     }
+
+    /**
+     * Taps outside task menu to dismiss it.
+     */
+    public void touchOutsideTaskMenuToDismiss() {
+        mLauncher.touchOutsideContainer(mMenu, false);
+    }
 }