Merge "Cleanup obsolete generated preview tests" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index f1f9966..15ac9e3 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -311,6 +311,13 @@
 }
 
 flag {
+    name: "enable_container_return_animations"
+    namespace: "launcher"
+    description: "Enables the container return animation mirroring launches."
+    bug: "341017746"
+}
+
+flag {
     name: "floating_search_bar"
     namespace: "launcher"
     description: "Search bar persists at the bottom of the screen across Launcher states"
diff --git a/go/quickstep/res/values-fa/strings.xml b/go/quickstep/res/values-fa/strings.xml
index 47786e9..8453d4e 100644
--- a/go/quickstep/res/values-fa/strings.xml
+++ b/go/quickstep/res/values-fa/strings.xml
@@ -14,7 +14,7 @@
     <string name="assistant_not_selected_text" msgid="3244613673884359276">"برای گوش کردن به نوشتار در صفحه‌نمایش‌تان یا ترجمه کردن آن، یکی از برنامه‌های دستیار دیجیتالی را در «تنظیمات» انتخاب کنید"</string>
     <string name="assistant_not_supported_title" msgid="1675788067597484142">"برای استفاده از این ویژگی، دستیارتان را تغییر دهید"</string>
     <string name="assistant_not_supported_text" msgid="1708031078549268884">"برای گوش کردن به نوشتار در صفحه‌نمایش‌تان یا ترجمه کردن آن، برنامه دستیار دیجیتالی‌تان را در «تنظیمات» تغییر دهید"</string>
-    <string name="tooltip_listen" msgid="7634466447860989102">"برای گوش کردن به نوشتار در این صفحه، اینجا ضربه بزنید"</string>
-    <string name="tooltip_translate" msgid="4184845868901542567">"برای ترجمه نوشتار در این صفحه، اینجا ضربه بزنید"</string>
+    <string name="tooltip_listen" msgid="7634466447860989102">"برای گوش کردن به نوشتار در این صفحه، اینجا تک‌ضرب بزنید"</string>
+    <string name="tooltip_translate" msgid="4184845868901542567">"برای ترجمه نوشتار در این صفحه، اینجا تک‌ضرب بزنید"</string>
     <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"نمی‌توان این برنامه را هم‌رسانی کرد"</string>
 </resources>
diff --git a/go/quickstep/res/values-nb/strings.xml b/go/quickstep/res/values-nb/strings.xml
index 662b544..6299cc8 100644
--- a/go/quickstep/res/values-nb/strings.xml
+++ b/go/quickstep/res/values-nb/strings.xml
@@ -9,7 +9,7 @@
     <string name="dialog_cancel" msgid="6464336969134856366">"AVBRYT"</string>
     <string name="dialog_settings" msgid="6564397136021186148">"INNSTILLINGER"</string>
     <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"Oversett eller lytt til tekst på skjermen"</string>
-    <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Informasjon som tekst på skjermen, nettadresser og skjermdumper kan deles med Google.\n\nFor å endre hvilken informasjon du deler, gå til "<b>"Innstillinger &gt; Apper &gt; Standardapper &gt; Digital assistent-app"</b>"."</string>
+    <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Informasjon som tekst på skjermen, nettadresser og skjermbilder kan deles med Google.\n\nFor å endre hvilken informasjon du deler, gå til "<b>"Innstillinger &gt; Apper &gt; Standardapper &gt; Digital assistent-app"</b>"."</string>
     <string name="assistant_not_selected_title" msgid="5017072974603345228">"Velg en assistent for å bruke denne funksjonen"</string>
     <string name="assistant_not_selected_text" msgid="3244613673884359276">"For å høre eller oversette tekst på skjermen, velg en digital assistent-app i innstillingene"</string>
     <string name="assistant_not_supported_title" msgid="1675788067597484142">"Endre assistenten for å bruke denne funksjonen"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index eedb29e..b84f646 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -87,7 +87,7 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Try again"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Nice!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <string name="allset_title" msgid="5021126669778966707">"Ready!"</string>
+    <string name="allset_title" msgid="5021126669778966707">"All set!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Swipe up to go home"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index eedb29e..b84f646 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -87,7 +87,7 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Try again"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Nice!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <string name="allset_title" msgid="5021126669778966707">"Ready!"</string>
+    <string name="allset_title" msgid="5021126669778966707">"All set!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Swipe up to go home"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index eedb29e..b84f646 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -87,7 +87,7 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Try again"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Nice!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <string name="allset_title" msgid="5021126669778966707">"Ready!"</string>
+    <string name="allset_title" msgid="5021126669778966707">"All set!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Swipe up to go home"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index b296080..bafc2d5 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -89,7 +89,7 @@
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"آموزش گام‌به‌گام <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"همه چیز آماده است!"</string>
     <string name="allset_hint" msgid="459504134589971527">"برای رفتن به صفحه اصلی، تند به‌بالا بکشید"</string>
-    <string name="allset_button_hint" msgid="2395219947744706291">"برای رفتن به صفحه اصلی، روی دکمه صفحه اصلی ضربه بزنید"</string>
+    <string name="allset_button_hint" msgid="2395219947744706291">"برای رفتن به صفحه اصلی، روی دکمه صفحه اصلی تک‌ضرب بزنید"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"آماده‌اید از <xliff:g id="DEVICE">%1$s</xliff:g> خود استفاده کنید"</string>
     <string name="default_device_name" msgid="6660656727127422487">"دستگاه"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"تنظیمات پیمایش سیستم"</annotation></string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 1f4275a..c27b7f8 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -141,7 +141,7 @@
     <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{데스크톱 앱 #개를 표시합니다.}other{데스크톱 앱 #개를 표시합니다.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"풍선"</string>
-    <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"오버플로"</string>
+    <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"더보기"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
     <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> 외 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>개"</string>
 </resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 7a4c7e9..fe2e4a4 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -141,7 +141,7 @@
     <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерын # аппыг харуулна уу.}other{Компьютерын # аппыг харуулна уу.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бөмбөлөг"</string>
-    <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Урт цэс"</string>
+    <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Илүү хэсэг"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>-с ирсэн <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
     <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> болон бусад <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
 </resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 47498cc..e4d07bd 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -113,7 +113,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arraste uma app para o lado para usar 2 apps em simultâneo"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Deslize lentamente para cima para ver a Barra de tarefas"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Receba sugestões de apps baseadas na sua rotina"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantenha o divisor premido para fixar a Barra de tarefas"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantenha o divisor pressionado para fixar a Barra de tarefas"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Faça mais com a Barra de tarefas"</string>
     <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostre sempre a Barra de tarefas"</string>
     <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para mostrar sempre a Barra de tarefas no fundo do ecrã, toque sem soltar no divisor"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index a89227e..79ea299 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -141,7 +141,7 @@
     <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{显示 # 款桌面应用。}other{显示 # 款桌面应用。}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"气泡框"</string>
-    <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"菜单"</string>
+    <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢出式气泡框"</string>
     <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"来自“<xliff:g id="APP_NAME">%2$s</xliff:g>”的<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
     <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>以及另外 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> 个"</string>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 15180ef..d973149 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -238,5 +238,12 @@
         @Override
         @UiThread
         default void onAnimationCancelled() {}
+
+        /**
+         * Returns whether this animation factory supports a tightly coupled return animation.
+         */
+        default boolean supportsReturnTransition() {
+            return false;
+        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index fae281a..5a74f4a 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -43,6 +43,7 @@
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
 import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
+import static com.android.launcher3.Flags.enableContainerReturnAnimations;
 import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
@@ -68,6 +69,7 @@
 import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
 import static com.android.quickstep.util.AnimUtils.clampToDuration;
 import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
+import static com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary;
 import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
 import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
 
@@ -181,6 +183,9 @@
  */
 public class QuickstepTransitionManager implements OnDeviceProfileChangeListener {
 
+    private static final String TRANSITION_COOKIE_PREFIX =
+            "com.android.launcher3.QuickstepTransitionManager_activityLaunch";
+
     private static final boolean ENABLE_SHELL_STARTING_SURFACE =
             SystemProperties.getBoolean("persist.debug.shell_starting_surface", true);
 
@@ -333,17 +338,7 @@
         restartedListener.register(onEndCallback::executeAllAndDestroy);
         onEndCallback.add(restartedListener::unregister);
 
-        mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
-        ItemInfo tag = (ItemInfo) v.getTag();
-        if (tag != null && tag.shouldUseBackgroundAnimation()) {
-            ContainerAnimationRunner containerAnimationRunner = ContainerAnimationRunner.from(
-                    v, mLauncher, mStartingWindowListener, onEndCallback);
-            if (containerAnimationRunner != null) {
-                mAppLaunchRunner = containerAnimationRunner;
-            }
-        }
-        RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(
-                mHandler, mAppLaunchRunner, true /* startAtFrontOfQueue */);
+        RemoteAnimationRunnerCompat runner = createAppLaunchRunner(v, onEndCallback);
 
         // Note that this duration is a guess as we do not know if the animation will be a
         // recents launch or not for sure until we know the opening app targets.
@@ -360,10 +355,95 @@
         IRemoteCallback endCallback = completeRunnableListCallback(onEndCallback);
         options.setOnAnimationAbortListener(endCallback);
         options.setOnAnimationFinishedListener(endCallback);
+
+        IBinder cookie = mAppLaunchRunner.supportsReturnTransition()
+                ? ((ContainerAnimationRunner) mAppLaunchRunner).getCookie() : null;
+        addLaunchCookie(cookie, (ItemInfo) v.getTag(), options);
+
+        // Register the return animation so it can be triggered on back from the app to home.
+        maybeRegisterAppReturnTransition(v);
+
         return new ActivityOptionsWrapper(options, onEndCallback);
     }
 
     /**
+     * Selects the appropriate type of launch runner for the given view, builds it, and returns it.
+     * {@link QuickstepTransitionManager#mAppLaunchRunner} is updated as a by-product of this
+     * method.
+     */
+    private RemoteAnimationRunnerCompat createAppLaunchRunner(View v, RunnableList onEndCallback) {
+        ItemInfo tag = (ItemInfo) v.getTag();
+        ContainerAnimationRunner containerRunner = null;
+        if (tag != null && tag.shouldUseBackgroundAnimation()) {
+            // The cookie should only override the default used by launcher if container return
+            // animations are enabled.
+            ActivityTransitionAnimator.TransitionCookie cookie =
+                    checkReturnAnimationsFlags()
+                            ? new ActivityTransitionAnimator.TransitionCookie(
+                                    TRANSITION_COOKIE_PREFIX + tag.id)
+                            : null;
+            ContainerAnimationRunner launchAnimationRunner =
+                    ContainerAnimationRunner.fromView(
+                            v, cookie, true /* forLaunch */, mLauncher, mStartingWindowListener,
+                            onEndCallback);
+
+            if (launchAnimationRunner != null) {
+                containerRunner = launchAnimationRunner;
+            }
+        }
+
+        mAppLaunchRunner = containerRunner != null
+                ? containerRunner : new AppLaunchAnimationRunner(v, onEndCallback);
+        return new LauncherAnimationRunner(
+                mHandler, mAppLaunchRunner, true /* startAtFrontOfQueue */);
+    }
+
+    /**
+     * If container return animations are enabled and the current launch runner is itself a
+     * {@link ContainerAnimationRunner}, registers a matching return animation that de-registers
+     * itself after it has run once or is made obsolete by the view going away.
+     */
+    private void maybeRegisterAppReturnTransition(View v) {
+        if (!checkReturnAnimationsFlags() || !mAppLaunchRunner.supportsReturnTransition()) {
+            return;
+        }
+
+        ActivityTransitionAnimator.TransitionCookie cookie =
+                ((ContainerAnimationRunner) mAppLaunchRunner).getCookie();
+        RunnableList onEndCallback = new RunnableList();
+        ContainerAnimationRunner runner =
+                ContainerAnimationRunner.fromView(
+                        v, cookie, false /* forLaunch */, mLauncher, mStartingWindowListener,
+                        onEndCallback);
+        RemoteTransition transition =
+                new RemoteTransition(
+                        new LauncherAnimationRunner(
+                                mHandler, runner, true /* startAtFrontOfQueue */
+                        ).toRemoteTransition()
+                );
+
+        SystemUiProxy.INSTANCE.get(mLauncher).registerRemoteTransition(
+                transition, ContainerAnimationRunner.buildBackToHomeFilter(cookie, mLauncher));
+        ContainerAnimationRunner.setUpRemoteAnimationCleanup(
+                v, transition, onEndCallback, mLauncher);
+    }
+
+    /**
+     * Adds a new launch cookie for the activity launch if supported.
+     * Prioritizes the explicitly provided cookie, falling back on extracting one from the given
+     * {@link ItemInfo} if necessary.
+     */
+    private void addLaunchCookie(IBinder cookie, ItemInfo info, ActivityOptions options) {
+        if (cookie == null) {
+            cookie = mLauncher.getLaunchCookie(info);
+        }
+
+        if (cookie != null) {
+            options.setLaunchCookie(cookie);
+        }
+    }
+
+    /**
      * Whether the launch is a recents app transition and we should do a launch animation
      * from the recents view. Note that if the remote animation targets are not provided, this
      * may not always be correct as we may resolve the opening app to a task when the animation
@@ -1728,6 +1808,10 @@
         }
     }
 
+    private static boolean checkReturnAnimationsFlags() {
+        return enableContainerReturnAnimations() && returnAnimationFrameworkLibrary();
+    }
+
     /**
      * Remote animation runner for animation from the app to Launcher, including recents.
      */
@@ -1844,38 +1928,45 @@
         /** The delegate runner that handles the actual animation. */
         private final RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> mDelegate;
 
+        @Nullable
+        private final ActivityTransitionAnimator.TransitionCookie mCookie;
+
         private ContainerAnimationRunner(
-                RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> delegate) {
+                RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> delegate,
+                ActivityTransitionAnimator.TransitionCookie cookie) {
             mDelegate = delegate;
+            mCookie = cookie;
         }
 
         @Nullable
-        private static ContainerAnimationRunner from(View v, Launcher launcher,
-                StartingWindowListener startingWindowListener, RunnableList onEndCallback) {
-            View viewToUse = findLaunchableViewWithBackground(v);
-            if (viewToUse == null) {
-                return null;
+        ActivityTransitionAnimator.TransitionCookie getCookie() {
+            return mCookie;
+        }
+
+        @Nullable
+        static ContainerAnimationRunner fromView(
+                View v,
+                ActivityTransitionAnimator.TransitionCookie cookie,
+                boolean forLaunch,
+                Launcher launcher,
+                StartingWindowListener startingWindowListener,
+                RunnableList onEndCallback) {
+            if (!forLaunch && !checkReturnAnimationsFlags()) {
+                throw new IllegalStateException(
+                        "forLaunch cannot be false when the enableContainerReturnAnimations or "
+                                + "returnAnimationFrameworkLibrary flag is disabled");
             }
 
-            // The CUJ is logged by the click handler, so we don't log it inside the animation
-            // library.
-            ActivityTransitionAnimator.Controller controllerDelegate =
-                    ActivityTransitionAnimator.Controller.fromView(viewToUse, null /* cujType */);
-
-            if (controllerDelegate == null) {
-                return null;
-            }
-
-            // This wrapper allows us to override the default value, telling the controller that the
-            // current window is below the animating window.
+            // First the controller is created. This is used by the runner to animate the
+            // origin/target view.
             ActivityTransitionAnimator.Controller controller =
-                    new DelegateTransitionAnimatorController(controllerDelegate) {
-                        @Override
-                        public boolean isBelowAnimatingWindow() {
-                            return true;
-                        }
-                    };
+                    buildController(v, cookie, forLaunch);
+            if (controller == null) {
+                return null;
+            }
 
+            // The callback is used to make sure that we use the right color to fade between view
+            // and the window.
             ActivityTransitionAnimator.Callback callback = task -> {
                 final int backgroundColor =
                         startingWindowListener.mBackgroundColor == Color.TRANSPARENT
@@ -1894,7 +1985,52 @@
 
             return new ContainerAnimationRunner(
                     new ActivityTransitionAnimator.AnimationDelegate(
-                            MAIN_EXECUTOR, controller, callback, listener));
+                            MAIN_EXECUTOR, controller, callback, listener),
+                    cookie);
+        }
+
+        /**
+         * Constructs a {@link ActivityTransitionAnimator.Controller} that can be used by a
+         * {@link ContainerAnimationRunner} to animate a view into an opening window or from a
+         * closing one.
+         */
+        @Nullable
+        private static ActivityTransitionAnimator.Controller buildController(
+                View v, ActivityTransitionAnimator.TransitionCookie cookie, boolean isLaunching) {
+            View viewToUse = findLaunchableViewWithBackground(v);
+            if (viewToUse == null) {
+                return null;
+            }
+
+            // The CUJ is logged by the click handler, so we don't log it inside the animation
+            // library. TODO: figure out return CUJ.
+            ActivityTransitionAnimator.Controller controllerDelegate =
+                    ActivityTransitionAnimator.Controller.fromView(viewToUse, null /* cujType */);
+
+            if (controllerDelegate == null) {
+                return null;
+            }
+
+            // This wrapper allows us to override the default value, telling the controller that the
+            // current window is below the animating window as well as information about the return
+            // animation.
+            return new DelegateTransitionAnimatorController(controllerDelegate) {
+                @Override
+                public boolean isLaunching() {
+                    return isLaunching;
+                }
+
+                @Override
+                public boolean isBelowAnimatingWindow() {
+                    return true;
+                }
+
+                @Nullable
+                @Override
+                public ActivityTransitionAnimator.TransitionCookie getTransitionCookie() {
+                    return cookie;
+                }
+            };
         }
 
         /**
@@ -1916,6 +2052,67 @@
             return (T) current;
         }
 
+        /**
+         * Builds the filter used by WM Shell to match app closing transitions (only back, no home
+         * button/gesture) to the given launch cookie.
+         */
+        static TransitionFilter buildBackToHomeFilter(
+                ActivityTransitionAnimator.TransitionCookie cookie, Launcher launcher) {
+            // Closing activity must include the cookie in its list of launch cookies.
+            TransitionFilter.Requirement appRequirement = new TransitionFilter.Requirement();
+            appRequirement.mActivityType = ACTIVITY_TYPE_STANDARD;
+            appRequirement.mLaunchCookie = cookie;
+            appRequirement.mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+            // Opening activity must be Launcher.
+            TransitionFilter.Requirement launcherRequirement = new TransitionFilter.Requirement();
+            launcherRequirement.mActivityType = ACTIVITY_TYPE_HOME;
+            launcherRequirement.mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+            launcherRequirement.mTopActivity = launcher.getComponentName();
+            // Transition types CLOSE and TO_BACK match the back button/gesture but not the  home
+            // button/gesture.
+            TransitionFilter filter = new TransitionFilter();
+            filter.mTypeSet = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+            filter.mRequirements =
+                    new TransitionFilter.Requirement[]{appRequirement, launcherRequirement};
+            return filter;
+        }
+
+        /**
+         * Creates various conditions to ensure that the given transition is cleaned up correctly
+         * when necessary:
+         * - if the transition has run, it is the callback that unregisters it;
+         * - if the associated view is detached before the transition has had an opportunity to run,
+         *   a {@link View.OnAttachStateChangeListener} allows us to do the same (and removes
+         *   itself).
+         */
+        static void setUpRemoteAnimationCleanup(
+                View v, RemoteTransition transition, RunnableList callback, Launcher launcher) {
+            View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() {
+                @Override
+                public void onViewAttachedToWindow(@NonNull View v) {}
+
+                @Override
+                public void onViewDetachedFromWindow(@NonNull View v) {
+                    SystemUiProxy.INSTANCE.get(launcher)
+                            .unregisterRemoteTransition(transition);
+                    v.removeOnAttachStateChangeListener(this);
+                }
+            };
+
+            // Remove the animation as soon as it has run once.
+            callback.add(() -> {
+                SystemUiProxy.INSTANCE.get(launcher).unregisterRemoteTransition(transition);
+                if (v != null) {
+                    v.removeOnAttachStateChangeListener(listener);
+                }
+            });
+
+            // Remove the animation when the view is detached from the hierarchy.
+            // This is so that if back is not invoked (e.g. if we go back home through the home
+            // gesture) we don't have obsolete transitions staying registered.
+            v.addOnAttachStateChangeListener(listener);
+        }
+
         @Override
         public void onAnimationStart(int transit, RemoteAnimationTarget[] appTargets,
                 RemoteAnimationTarget[] wallpaperTargets, RemoteAnimationTarget[] nonAppTargets,
@@ -1928,6 +2125,11 @@
         public void onAnimationCancelled() {
             mDelegate.onAnimationCancelled();
         }
+
+        @Override
+        public boolean supportsReturnTransition() {
+            return true;
+        }
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 7e52ea1..7cdca74 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -120,10 +120,6 @@
         WindowInsetsController wc = mDragLayer.getWindowInsetsController();
         wc.hide(navigationBars() + statusBars());
 
-        BaseWidgetSheet widgetSheet = WidgetsFullSheet.show(this, true);
-        widgetSheet.disableNavBarScrim(true);
-        widgetSheet.addOnCloseListener(this::finish);
-
         parseIntentExtras();
         refreshAndBindWidgets();
     }
@@ -224,9 +220,10 @@
         };
     }
 
-    /** Updates the model with widgets and provides them after applying the provided filter. */
+    /** Updates the model with widgets, applies filters and launches the widgets sheet once
+     * widgets are available */
     private void refreshAndBindWidgets() {
-        MODEL_EXECUTOR.execute(() -> {
+        MODEL_EXECUTOR.getHandler().postDelayed(() -> {
             LauncherAppState app = LauncherAppState.getInstance(this);
             mModel.update(app, null);
             final List<WidgetsListBaseEntry> allWidgets =
@@ -240,6 +237,9 @@
                             }
                     );
             bindWidgets(allWidgets);
+            // Open sheet once widgets are available, so that it doesn't interrupt the open
+            // animation.
+            openWidgetsSheet();
             if (mUiSurface != null) {
                 Map<ComponentKey, WidgetItem> allWidgetItems = allWidgets.stream()
                         .filter(entry -> entry instanceof WidgetsListContentEntry)
@@ -253,15 +253,26 @@
                         mUiSurface, allWidgetItems);
                 mWidgetPredictionsRequester.request(mAddedWidgets, this::bindRecommendedWidgets);
             }
-        });
+        }, mDeviceProfile.bottomSheetOpenDuration);
     }
 
     private void bindWidgets(List<WidgetsListBaseEntry> widgets) {
         MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setAllWidgets(widgets));
     }
 
+    private void openWidgetsSheet() {
+        MAIN_EXECUTOR.execute(() -> {
+            BaseWidgetSheet widgetSheet = WidgetsFullSheet.show(this, true);
+            widgetSheet.disableNavBarScrim(true);
+            widgetSheet.addOnCloseListener(this::finish);
+        });
+    }
+
     private void bindRecommendedWidgets(List<ItemInfo> recommendedWidgets) {
-        MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setRecommendedWidgets(recommendedWidgets));
+        // Bind recommendations once picker has finished open animation.
+        MAIN_EXECUTOR.getHandler().postDelayed(
+                () -> mPopupDataProvider.setRecommendedWidgets(recommendedWidgets),
+                mDeviceProfile.bottomSheetOpenDuration);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java b/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java
index 5730273..41fcf61 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java
@@ -65,6 +65,7 @@
     private final Context mContext;
     @NonNull
     private final String mUiSurface;
+    private boolean mPredictionsAvailable;
     @NonNull
     private final Map<ComponentKey, WidgetItem> mAllWidgets;
 
@@ -76,8 +77,8 @@
     }
 
     /**
-     * Requests predictions from the app predictions manager and registers the provided callback to
-     * receive updates when predictions are available.
+     * Requests one time predictions from the app predictions manager and invokes provided callback
+     * once predictions are available.
      *
      * @param existingWidgets widgets that are currently added to the surface;
      * @param callback        consumer of prediction results to be called when predictions are
@@ -159,10 +160,14 @@
     @WorkerThread
     private void bindPredictions(List<AppTarget> targets, Predicate<WidgetItem> filter,
             Consumer<List<ItemInfo>> callback) {
-        List<WidgetItem> filteredPredictions = filterPredictions(targets, mAllWidgets, filter);
-        List<ItemInfo> mappedPredictions = mapWidgetItemsToItemInfo(filteredPredictions);
+        if (!mPredictionsAvailable) {
+            mPredictionsAvailable = true;
+            List<WidgetItem> filteredPredictions = filterPredictions(targets, mAllWidgets, filter);
+            List<ItemInfo> mappedPredictions = mapWidgetItemsToItemInfo(filteredPredictions);
 
-        MAIN_EXECUTOR.execute(() -> callback.accept(mappedPredictions));
+            MAIN_EXECUTOR.execute(() -> callback.accept(mappedPredictions));
+            MODEL_EXECUTOR.execute(this::clear);
+        }
     }
 
     /**
@@ -214,5 +219,6 @@
             mAppPredictor.destroy();
             mAppPredictor = null;
         }
+        mPredictionsAvailable = false;
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index ce281c3..f24bc21 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -269,8 +269,8 @@
                                     foundTaskView,
                                     foundTask,
                                     taskContainer.getIconView().getDrawable(),
-                                    taskContainer.getThumbnailViewDeprecated(),
-                                    taskContainer.getThumbnailViewDeprecated().getThumbnail(),
+                                    taskContainer.getSnapshotView(),
+                                    taskContainer.getThumbnail(),
                                     null /* intent */,
                                     null /* user */,
                                     info);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 037f2f6..be6f690 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1200,7 +1200,6 @@
                         : Display.DEFAULT_DISPLAY);
         activityOptions.options.setPendingIntentBackgroundActivityStartMode(
                 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
-        addLaunchCookie(item, activityOptions.options);
         return activityOptions;
     }
 
@@ -1225,19 +1224,6 @@
     }
 
     /**
-     * Adds a new launch cookie for the activity launch if supported.
-     *
-     * @param info the item info for the launch
-     * @param opts the options to set the launchCookie on.
-     */
-    public void addLaunchCookie(ItemInfo info, ActivityOptions opts) {
-        IBinder launchCookie = getLaunchCookie(info);
-        if (launchCookie != null) {
-            opts.setLaunchCookie(launchCookie);
-        }
-    }
-
-    /**
      * Return a new launch cookie for the activity launch if supported.
      *
      * @param info the item info for the launch
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 4bc3c16..3c7f335 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -252,7 +252,7 @@
                     mTaskBeingDragged, maxDuration, currentInterpolator);
 
             // Since the thumbnail is what is filling the screen, based the end displacement on it.
-            View thumbnailView = mTaskBeingDragged.getFirstThumbnailViewDeprecated();
+            View thumbnailView = mTaskBeingDragged.getFirstSnapshotView();
             mTempCords[1] = orientationHandler.getSecondaryDimension(thumbnailView);
             dl.getDescendantCoordRelativeToSelf(thumbnailView, mTempCords);
             mEndDisplacement = secondaryLayerDimension - mTempCords[1];
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 66091d4..3d4167a 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -44,6 +44,7 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Consumer;
@@ -324,7 +325,9 @@
                 // leftover TYPE_FREEFORM tasks created when flag was on should be ignored.
                 if (enableDesktopWindowingMode()) {
                     GroupTask desktopTask = createDesktopTask(rawTask);
-                    allTasks.add(desktopTask);
+                    if (desktopTask != null) {
+                        allTasks.add(desktopTask);
+                    }
                 }
                 continue;
             }
@@ -368,8 +371,13 @@
         return allTasks;
     }
 
-    private DesktopTask createDesktopTask(GroupedRecentTaskInfo recentTaskInfo) {
+    private @Nullable DesktopTask createDesktopTask(GroupedRecentTaskInfo recentTaskInfo) {
         ArrayList<Task> tasks = new ArrayList<>(recentTaskInfo.getTaskInfoList().size());
+        int[] minimizedTaskIds = recentTaskInfo.getMinimizedTaskIds();
+        if (minimizedTaskIds.length == recentTaskInfo.getTaskInfoList().size()) {
+            // All Tasks are minimized -> don't create a DesktopTask
+            return null;
+        }
         for (ActivityManager.RecentTaskInfo taskInfo : recentTaskInfo.getTaskInfoList()) {
             Task.TaskKey key = new Task.TaskKey(taskInfo);
             Task task = Task.from(key, taskInfo, false);
@@ -377,6 +385,8 @@
             task.positionInParent = taskInfo.positionInParent;
             task.appBounds = taskInfo.configuration.windowConfiguration.getAppBounds();
             task.isVisible = taskInfo.isVisible;
+            task.isMinimized =
+                    Arrays.stream(minimizedTaskIds).anyMatch(taskId -> taskId == taskInfo.taskId);
             tasks.add(task);
         }
         return new DesktopTask(tasks);
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index b183ae3..5d0d074 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -44,7 +44,6 @@
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.RecentsViewContainer;
-import com.android.quickstep.views.TaskThumbnailViewDeprecated;
 import com.android.quickstep.views.TaskView;
 import com.android.quickstep.views.TaskView.TaskContainer;
 import com.android.systemui.shared.recents.model.Task;
@@ -134,20 +133,20 @@
             mApplicationContext = taskContainer.getTaskView().getContext().getApplicationContext();
             mTaskContainer = taskContainer;
             mImageApi = new ImageActionsApi(
-                    mApplicationContext, mTaskContainer.getThumbnailViewDeprecated()::getThumbnail);
+                    mApplicationContext, mTaskContainer::getThumbnail);
         }
 
         protected T getActionsView() {
             if (mActionsView == null) {
                 mActionsView = BaseActivity.fromContext(
-                        mTaskContainer.getThumbnailViewDeprecated().getContext()).findViewById(
+                        mTaskContainer.getTaskView().getContext()).findViewById(
                         R.id.overview_actions_view);
             }
             return mActionsView;
         }
 
-        public TaskThumbnailViewDeprecated getThumbnailView() {
-            return mTaskContainer.getThumbnailViewDeprecated();
+        public TaskView getTaskView() {
+            return mTaskContainer.getTaskView();
         }
 
         /**
@@ -159,8 +158,7 @@
 
             if (thumbnail != null) {
                 getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated);
-                boolean isAllowedByPolicy =
-                        mTaskContainer.getThumbnailViewDeprecated().isRealSnapshot();
+                boolean isAllowedByPolicy = mTaskContainer.isRealSnapshot();
                 getActionsView().setCallbacks(new OverlayUICallbacksImpl(isAllowedByPolicy, task));
             }
         }
@@ -172,7 +170,7 @@
          */
         public void endLiveTileMode(@NonNull Runnable callback) {
             RecentsView recentsView =
-                    mTaskContainer.getThumbnailViewDeprecated().getTaskView().getRecentsView();
+                    mTaskContainer.getTaskView().getRecentsView();
             // Task has already been dismissed
             if (recentsView == null) return;
             recentsView.switchToScreenshot(
@@ -185,8 +183,8 @@
          */
         @SuppressLint("NewApi")
         protected void saveScreenshot(Task task) {
-            if (mTaskContainer.getThumbnailViewDeprecated().isRealSnapshot()) {
-                mImageApi.saveScreenshot(mTaskContainer.getThumbnailViewDeprecated().getThumbnail(),
+            if (mTaskContainer.isRealSnapshot()) {
+                mImageApi.saveScreenshot(mTaskContainer.getThumbnail(),
                         getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key);
             } else {
                 showBlockedByPolicyMessage();
@@ -194,17 +192,14 @@
         }
 
         protected void enterSplitSelect() {
-            RecentsView overviewPanel =
-                    mTaskContainer.getThumbnailViewDeprecated().getTaskView().getRecentsView();
+            RecentsView overviewPanel = mTaskContainer.getTaskView().getRecentsView();
             // Task has already been dismissed
             if (overviewPanel == null) return;
-            overviewPanel.initiateSplitSelect(
-                    mTaskContainer.getThumbnailViewDeprecated().getTaskView());
+            overviewPanel.initiateSplitSelect(mTaskContainer.getTaskView());
         }
 
         protected void saveAppPair() {
-            GroupedTaskView taskView =
-                    (GroupedTaskView) mTaskContainer.getThumbnailViewDeprecated().getTaskView();
+            GroupedTaskView taskView = (GroupedTaskView) mTaskContainer.getTaskView();
             taskView.getRecentsView().getSplitSelectController().getAppPairsController()
                     .saveAppPair(taskView);
         }
@@ -250,11 +245,11 @@
          */
         public Rect getTaskSnapshotBounds() {
             int[] location = new int[2];
-            mTaskContainer.getThumbnailViewDeprecated().getLocationOnScreen(location);
+            mTaskContainer.getSnapshotView().getLocationOnScreen(location);
 
             return new Rect(location[0], location[1],
-                    mTaskContainer.getThumbnailViewDeprecated().getWidth() + location[0],
-                    mTaskContainer.getThumbnailViewDeprecated().getHeight() + location[1]);
+                    mTaskContainer.getSnapshotView().getWidth() + location[0],
+                    mTaskContainer.getSnapshotView().getHeight() + location[1]);
         }
 
         /**
@@ -264,7 +259,7 @@
          */
         @RequiresApi(api = Build.VERSION_CODES.Q)
         public Insets getTaskSnapshotInsets() {
-            return mTaskContainer.getThumbnailViewDeprecated().getScaledInsets();
+            return mTaskContainer.getScaledInsets();
         }
 
         /**
@@ -275,14 +270,14 @@
 
         protected void showBlockedByPolicyMessage() {
             ActivityContext activityContext = ActivityContext.lookupContext(
-                    mTaskContainer.getThumbnailViewDeprecated().getContext());
+                    mTaskContainer.getTaskView().getContext());
             String message = activityContext.getStringCache() != null
                     ? activityContext.getStringCache().disabledByAdminMessage
-                    : mTaskContainer.getThumbnailViewDeprecated().getContext().getString(
+                    : mTaskContainer.getTaskView().getContext().getString(
                             R.string.blocked_by_policy);
 
             Snackbar.show(BaseActivity.fromContext(
-                    mTaskContainer.getThumbnailViewDeprecated().getContext()), message, null);
+                    mTaskContainer.getTaskView().getContext()), message, null);
         }
 
         /** Called when the snapshot has updated its full screen drawing parameters. */
@@ -304,8 +299,7 @@
 
             @Override
             public void onClick(View view) {
-                saveScreenshot(
-                        mTaskContainer.getThumbnailViewDeprecated().getTaskView().getFirstTask());
+                saveScreenshot(mTaskContainer.getTaskView().getFirstTask());
                 dismissTaskMenuView();
             }
         }
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 4691ea9..b4862fd 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -20,6 +20,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.view.Surface.ROTATION_0;
 
+import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.window.flags.Flags.enableDesktopWindowingMode;
@@ -55,7 +56,6 @@
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.RecentsViewContainer;
-import com.android.quickstep.views.TaskThumbnailViewDeprecated;
 import com.android.quickstep.views.TaskView;
 import com.android.quickstep.views.TaskView.TaskContainer;
 import com.android.systemui.shared.recents.model.Task;
@@ -174,7 +174,7 @@
         private Handler mHandler;
 
         private final RecentsView mRecentsView;
-        private final TaskThumbnailViewDeprecated mThumbnailView;
+        private final TaskContainer mTaskContainer;
         private final TaskView mTaskView;
         private final LauncherEvent mLauncherEvent;
 
@@ -186,7 +186,7 @@
             mHandler = new Handler(Looper.getMainLooper());
             mTaskView = taskContainer.getTaskView();
             mRecentsView = container.getOverviewPanel();
-            mThumbnailView = taskContainer.getThumbnailViewDeprecated();
+            mTaskContainer = taskContainer;
         }
 
         @Override
@@ -220,20 +220,25 @@
                 };
 
                 final int[] position = new int[2];
-                mThumbnailView.getLocationOnScreen(position);
-                final int width = (int) (mThumbnailView.getWidth() * mTaskView.getScaleX());
-                final int height = (int) (mThumbnailView.getHeight() * mTaskView.getScaleY());
+                View snapShotView = mTaskContainer.getSnapshotView();
+                snapShotView.getLocationOnScreen(position);
+                final int width = (int) (snapShotView.getWidth() * mTaskView.getScaleX());
+                final int height = (int) (snapShotView.getHeight() * mTaskView.getScaleY());
                 final Rect taskBounds = new Rect(position[0], position[1],
                         position[0] + width, position[1] + height);
 
                 // Take the thumbnail of the task without a scrim and apply it back after
-                float alpha = mThumbnailView.getDimAlpha();
                 // TODO(b/348643341) add ability to get override the scrim for this Bitmap retrieval
-                mThumbnailView.setDimAlpha(0);
+                float alpha = 0f;
+                if (!enableRefactorTaskThumbnail()) {
+                    alpha = mTaskContainer.getThumbnailViewDeprecated().getDimAlpha();
+                    mTaskContainer.getThumbnailViewDeprecated().setDimAlpha(0);
+                }
                 Bitmap thumbnail = RecentsTransition.drawViewIntoHardwareBitmap(
-                        taskBounds.width(), taskBounds.height(), mThumbnailView, 1f,
-                        Color.BLACK);
-                mThumbnailView.setDimAlpha(alpha);
+                        taskBounds.width(), taskBounds.height(), snapShotView, 1f, Color.BLACK);
+                if (!enableRefactorTaskThumbnail()) {
+                    mTaskContainer.getThumbnailViewDeprecated().setDimAlpha(alpha);
+                }
 
                 AppTransitionAnimationSpecsFuture future =
                         new AppTransitionAnimationSpecsFuture(mHandler) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index ecd84f8..bd44283 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -80,7 +80,6 @@
 import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskThumbnailViewDeprecated;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.animation.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.recents.model.Task;
@@ -334,7 +333,7 @@
             // During animation we apply transformation on the thumbnailView (and not the rootView)
             // to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
             //    Mt K(0)` K(t) Mt`
-            TaskThumbnailViewDeprecated[] thumbnails = v.getThumbnailViews();
+            View[] thumbnails = v.getSnapshotViews();
 
             // In case simulator copies and thumbnail size do no match, ensure we get the lesser.
             // This ensures we do not create arrays with empty elements or attempt to references
@@ -344,7 +343,7 @@
             Matrix[] mt = new Matrix[matrixSize];
             Matrix[] mti = new Matrix[matrixSize];
             for (int i = 0; i < matrixSize; i++) {
-                TaskThumbnailViewDeprecated ttv = thumbnails[i];
+                View ttv = thumbnails[i];
                 RectF localBounds = new RectF(0, 0,  ttv.getWidth(), ttv.getHeight());
                 float[] tvBoundsMapped = new float[]{0, 0,  ttv.getWidth(), ttv.getHeight()};
                 getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
@@ -391,7 +390,7 @@
             out.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    for (TaskThumbnailViewDeprecated ttv : thumbnails) {
+                    for (View ttv : thumbnails) {
                         ttv.setAnimationMatrix(null);
                     }
                 }
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 7ea04b1..876a4ea 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -43,6 +43,7 @@
 import com.android.app.animation.Interpolators
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.Flags.enableOverviewIconMenu
+import com.android.launcher3.Flags.enableRefactorTaskThumbnail
 import com.android.launcher3.InsettableFrameLayout
 import com.android.launcher3.QuickstepTransitionManager
 import com.android.launcher3.R
@@ -118,8 +119,8 @@
                 if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) {
                     val drawable = getDrawable(container.iconView, splitSelectSource)
                     return SplitAnimInitProps(
-                        container.thumbnailViewDeprecated,
-                        container.thumbnailViewDeprecated.thumbnail,
+                        container.snapshotView,
+                        container.thumbnail,
                         drawable!!,
                         fadeWithThumbnail = true,
                         isStagedTask = true,
@@ -137,8 +138,8 @@
             taskView.taskContainers.first().let {
                 val drawable = getDrawable(it.iconView, splitSelectSource)
                 return SplitAnimInitProps(
-                    it.thumbnailViewDeprecated,
-                    it.thumbnailViewDeprecated.thumbnail,
+                    it.snapshotView,
+                    it.thumbnail,
                     drawable!!,
                     fadeWithThumbnail = true,
                     isStagedTask = true,
@@ -165,27 +166,37 @@
     /**
      * When selecting first app from split pair, second app's thumbnail remains. This animates the
      * second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying it
-     * with [TaskThumbnailViewDeprecated]'s splashView. Adds animations to the provided builder.
-     * Note: The app that **was not** selected as the first split app should be the container that's
-     * passed through.
+     * with [TaskContainer]'s splashView. Adds animations to the provided builder. Note: The app
+     * that **was not** selected as the first split app should be the container that's passed
+     * through.
      *
      * @param builder Adds animation to this
-     * @param taskIdAttributeContainer container of the app that **was not** selected
+     * @param taskContainer container of the app that **was not** selected
      * @param isPrimaryTaskSplitting if true, task that was split would be top/left in the pair
-     *   (opposite of that representing [taskIdAttributeContainer])
+     *   (opposite of that representing [taskContainer])
      */
     fun addInitialSplitFromPair(
-        taskIdAttributeContainer: TaskContainer,
+        taskContainer: TaskContainer,
         builder: PendingAnimation,
         deviceProfile: DeviceProfile,
         taskViewWidth: Int,
         taskViewHeight: Int,
         isPrimaryTaskSplitting: Boolean
     ) {
-        val thumbnail = taskIdAttributeContainer.thumbnailViewDeprecated
-        val iconView: View = taskIdAttributeContainer.iconView.asView()
-        builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailViewDeprecated.SPLASH_ALPHA, 1f))
-        thumbnail.setShowSplashForSplitSelection(true)
+        val snapshot = taskContainer.snapshotView
+        val iconView: View = taskContainer.iconView.asView()
+        // TODO(334826842): Switch to splash state in TaskThumbnailView
+        if (!enableRefactorTaskThumbnail()) {
+            val thumbnailViewDeprecated = taskContainer.thumbnailViewDeprecated
+            builder.add(
+                ObjectAnimator.ofFloat(
+                    thumbnailViewDeprecated,
+                    TaskThumbnailViewDeprecated.SPLASH_ALPHA,
+                    1f
+                )
+            )
+            thumbnailViewDeprecated.setShowSplashForSplitSelection(true)
+        }
         // With the new `IconAppChipView`, we always want to keep the chip pinned to the
         // top left of the task / thumbnail.
         if (enableOverviewIconMenu()) {
@@ -202,14 +213,10 @@
         }
         if (deviceProfile.isLeftRightSplit) {
             // Center view first so scaling happens uniformly, alternatively we can move pivotX to 0
-            val centerThumbnailTranslationX: Float = (taskViewWidth - thumbnail.width) / 2f
-            val finalScaleX: Float = taskViewWidth.toFloat() / thumbnail.width
+            val centerThumbnailTranslationX: Float = (taskViewWidth - snapshot.width) / 2f
+            val finalScaleX: Float = taskViewWidth.toFloat() / snapshot.width
             builder.add(
-                ObjectAnimator.ofFloat(
-                    thumbnail,
-                    TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_X,
-                    centerThumbnailTranslationX
-                )
+                ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_X, centerThumbnailTranslationX)
             )
             if (!enableOverviewIconMenu()) {
                 // icons are anchored from Gravity.END, so need to use negative translation
@@ -218,21 +225,15 @@
                     ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X, -centerIconTranslationX)
                 )
             }
-            builder.add(ObjectAnimator.ofFloat(thumbnail, View.SCALE_X, finalScaleX))
+            builder.add(ObjectAnimator.ofFloat(snapshot, View.SCALE_X, finalScaleX))
 
             // Reset other dimensions
             // TODO(b/271468547), can't set Y translate to 0, need to account for top space
-            thumbnail.scaleY = 1f
+            snapshot.scaleY = 1f
             val translateYResetVal: Float =
                 if (!isPrimaryTaskSplitting) 0f
                 else deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
-            builder.add(
-                ObjectAnimator.ofFloat(
-                    thumbnail,
-                    TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
-                    translateYResetVal
-                )
-            )
+            builder.add(ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_Y, translateYResetVal))
         } else {
             val thumbnailSize = taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
             // Center view first so scaling happens uniformly, alternatively we can move pivotY to 0
@@ -247,36 +248,26 @@
             //  thumbnail needs to take that into account. We should migrate to only using
             //  translations otherwise this asymmetry causes problems..
             if (isPrimaryTaskSplitting) {
-                centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f
+                centerThumbnailTranslationY = (thumbnailSize - snapshot.height) / 2f
                 centerThumbnailTranslationY +=
                     deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
             } else {
-                centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f
+                centerThumbnailTranslationY = (thumbnailSize - snapshot.height) / 2f
             }
-            val finalScaleY: Float = thumbnailSize.toFloat() / thumbnail.height
+            val finalScaleY: Float = thumbnailSize.toFloat() / snapshot.height
             builder.add(
-                ObjectAnimator.ofFloat(
-                    thumbnail,
-                    TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_Y,
-                    centerThumbnailTranslationY
-                )
+                ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_Y, centerThumbnailTranslationY)
             )
 
             if (!enableOverviewIconMenu()) {
                 // icons are anchored from Gravity.END, so need to use negative translation
                 builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X, 0f))
             }
-            builder.add(ObjectAnimator.ofFloat(thumbnail, View.SCALE_Y, finalScaleY))
+            builder.add(ObjectAnimator.ofFloat(snapshot, View.SCALE_Y, finalScaleY))
 
             // Reset other dimensions
-            thumbnail.scaleX = 1f
-            builder.add(
-                ObjectAnimator.ofFloat(
-                    thumbnail,
-                    TaskThumbnailViewDeprecated.SPLIT_SELECT_TRANSLATE_X,
-                    0f
-                )
-            )
+            snapshot.scaleX = 1f
+            builder.add(ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_X, 0f))
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
index 38bbe60..4820c35 100644
--- a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
@@ -31,29 +31,13 @@
                 null
             } else {
                 SplitConfigurationOptions.SplitBounds(
-                    shellSplitBounds.leftTopBounds, shellSplitBounds.rightBottomBounds,
-                    shellSplitBounds.leftTopTaskId, shellSplitBounds.rightBottomTaskId,
+                    shellSplitBounds.leftTopBounds,
+                    shellSplitBounds.rightBottomBounds,
+                    shellSplitBounds.leftTopTaskId,
+                    shellSplitBounds.rightBottomTaskId,
                     shellSplitBounds.snapPosition
                 )
             }
         }
-
-        /** Converts the launcher version of SplitBounds to the shell version */
-        @JvmStatic
-        fun convertLauncherSplitBoundsToShell(
-            launcherSplitBounds: SplitConfigurationOptions.SplitBounds?
-        ): SplitBounds? {
-            return if (launcherSplitBounds == null) {
-                null
-            } else {
-                SplitBounds(
-                    launcherSplitBounds.leftTopBounds,
-                    launcherSplitBounds.rightBottomBounds,
-                    launcherSplitBounds.leftTopTaskId,
-                    launcherSplitBounds.rightBottomTaskId,
-                    launcherSplitBounds.snapPosition
-                )
-            }
-        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 49f4e5f..d9b7d20 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -27,7 +27,6 @@
 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
 import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
-import static com.android.quickstep.util.SplitScreenUtils.convertLauncherSplitBoundsToShell;
 
 import android.animation.TimeInterpolator;
 import android.content.Context;
@@ -247,8 +246,6 @@
         } else {
             mStagePosition = runningTarget.taskId == splitInfo.leftTopTaskId
                     ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
-            mPositionHelper.setSplitBounds(convertLauncherSplitBoundsToShell(mSplitBounds),
-                    mStagePosition);
         }
         calculateTaskSize();
     }
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 4c78e21..46ed2ee 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -128,7 +128,7 @@
                     }
             val thumbWidth = (taskSize.width() * scaleWidth).toInt()
             val thumbHeight = (taskSize.height() * scaleHeight).toInt()
-            it.thumbnailViewDeprecated.measure(
+            it.snapshotView.measure(
                 MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY)
             )
@@ -139,8 +139,8 @@
             var taskY = (positionInParent.y * scaleHeight).toInt()
             // move task down by margin size
             taskY += thumbnailTopMarginPx
-            it.thumbnailViewDeprecated.x = taskX.toFloat()
-            it.thumbnailViewDeprecated.y = taskY.toFloat()
+            it.snapshotView.x = taskX.toFloat()
+            it.snapshotView.y = taskY.toFloat()
             if (DEBUG) {
                 Log.d(
                     TAG,
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 4a5b9e4..9f268a0 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -332,12 +332,12 @@
                 (FrameLayout.LayoutParams) mBanner.getLayoutParams();
         DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
-                mTaskView.getFirstThumbnailViewDeprecated().getLayoutParams()).bottomMargin;
+                mTaskView.getFirstSnapshotView().getLayoutParams()).bottomMargin;
         RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
         Pair<Float, Float> translations = orientationHandler
                 .getDwbLayoutTranslations(mTaskView.getMeasuredWidth(),
                         mTaskView.getMeasuredHeight(), mSplitBounds, deviceProfile,
-                        mTaskView.getThumbnailViews(), mTask.key.id, mBanner);
+                        mTaskView.getSnapshotViews(), mTask.key.id, mBanner);
         mSplitOffsetTranslationX = translations.first;
         mSplitOffsetTranslationY = translations.second;
         updateTranslationY();
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index 6296b0e..b070244 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -33,10 +33,8 @@
 import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
 import com.android.quickstep.TaskOverlayFactory
 import com.android.quickstep.util.RecentsOrientedState
-import com.android.quickstep.util.SplitScreenUtils.Companion.convertLauncherSplitBoundsToShell
 import com.android.quickstep.util.SplitSelectStateController
 import com.android.systemui.shared.recents.model.Task
-import com.android.systemui.shared.recents.utilities.PreviewPositionHelper
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper
 import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition
 
@@ -70,36 +68,20 @@
         val initSplitTaskId = getThisTaskCurrentlyInSplitSelection()
         if (initSplitTaskId == INVALID_TASK_ID) {
             pagedOrientationHandler.measureGroupedTaskViewThumbnailBounds(
-                taskContainers[0].thumbnailViewDeprecated,
-                taskContainers[1].thumbnailViewDeprecated,
+                taskContainers[0].snapshotView,
+                taskContainers[1].snapshotView,
                 widthSize,
                 heightSize,
                 splitBoundsConfig,
                 container.deviceProfile,
                 layoutDirection == LAYOUT_DIRECTION_RTL
             )
-            // Should we be having a separate translation step apart from the measuring above?
-            // The following only applies to large screen for now, but for future reference
-            // we'd want to abstract this out in PagedViewHandlers to get the primary/secondary
-            // translation directions
-            taskContainers[0]
-                .thumbnailViewDeprecated
-                .applySplitSelectTranslateX(taskContainers[0].thumbnailViewDeprecated.translationX)
-            taskContainers[0]
-                .thumbnailViewDeprecated
-                .applySplitSelectTranslateY(taskContainers[0].thumbnailViewDeprecated.translationY)
-            taskContainers[1]
-                .thumbnailViewDeprecated
-                .applySplitSelectTranslateX(taskContainers[1].thumbnailViewDeprecated.translationX)
-            taskContainers[1]
-                .thumbnailViewDeprecated
-                .applySplitSelectTranslateY(taskContainers[1].thumbnailViewDeprecated.translationY)
         } else {
             // Currently being split with this taskView, let the non-split selected thumbnail
             // take up full thumbnail area
             taskContainers
                 .firstOrNull { it.task.key.id != initSplitTaskId }
-                ?.thumbnailViewDeprecated
+                ?.snapshotView
                 ?.measure(
                     widthMeasureSpec,
                     MeasureSpec.makeMeasureSpec(
@@ -147,23 +129,7 @@
             )
         taskContainers.forEach { it.bind() }
 
-        this.splitBoundsConfig =
-            splitBoundsConfig?.also {
-                taskContainers[0]
-                    .thumbnailViewDeprecated
-                    .previewPositionHelper
-                    .setSplitBounds(
-                        convertLauncherSplitBoundsToShell(it),
-                        PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT
-                    )
-                taskContainers[1]
-                    .thumbnailViewDeprecated
-                    .previewPositionHelper
-                    .setSplitBounds(
-                        convertLauncherSplitBoundsToShell(it),
-                        PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT
-                    )
-            }
+        this.splitBoundsConfig = splitBoundsConfig
         taskContainers.forEach { it.digitalWellBeingToast?.setSplitBounds(splitBoundsConfig) }
         setOrientationState(orientedState)
     }
@@ -230,8 +196,8 @@
                 taskContainers[0].iconView.asView(),
                 taskContainers[1].iconView.asView(),
                 taskIconHeight,
-                taskContainers[0].thumbnailViewDeprecated.measuredWidth,
-                taskContainers[0].thumbnailViewDeprecated.measuredHeight,
+                taskContainers[0].snapshotView.measuredWidth,
+                taskContainers[0].snapshotView.measuredHeight,
                 measuredHeight,
                 measuredWidth,
                 isRtl,
@@ -326,7 +292,7 @@
         // Check which of the two apps was selected
         if (
             taskContainers[1].iconView.asView().containsPoint(lastTouchDownPosition) ||
-                taskContainers[1].thumbnailViewDeprecated.containsPoint(lastTouchDownPosition)
+                taskContainers[1].snapshotView.containsPoint(lastTouchDownPosition)
         ) {
             return 1
         }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index d806e3d..c1e112a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1826,8 +1826,13 @@
                 ((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState,
                         mTaskOverlayFactory, groupTask.mSplitBounds);
             } else if (taskView instanceof DesktopTaskView) {
-                ((DesktopTaskView) taskView).bind(((DesktopTask) groupTask).tasks,
-                        mOrientationState, mTaskOverlayFactory);
+                // Minimized tasks should not be shown in Overview
+                List<Task> nonMinimizedTasks =
+                        ((DesktopTask) groupTask).tasks.stream()
+                                .filter(task -> !task.isMinimized)
+                                .toList();
+                ((DesktopTaskView) taskView).bind(nonMinimizedTasks, mOrientationState,
+                        mTaskOverlayFactory);
                 mDesktopTaskView = (DesktopTaskView) taskView;
             } else {
                 Task task = groupTask.task1.key.id == stagedTaskIdToBeRemoved ? groupTask.task2
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 4f446b2..8d5ba77 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -238,12 +238,12 @@
         mContainer.getDragLayer().getDescendantRectRelativeToSelf(
                 enableOverviewIconMenu()
                         ? getIconView().findViewById(R.id.icon_view_menu_anchor)
-                        : taskContainer.getThumbnailViewDeprecated(),
+                        : taskContainer.getSnapshotView(),
                 sTempRect);
         Rect insets = mContainer.getDragLayer().getInsets();
         BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
         params.width = orientationHandler.getTaskMenuWidth(
-                taskContainer.getThumbnailViewDeprecated(), deviceProfile,
+                taskContainer.getSnapshotView(), deviceProfile,
                 taskContainer.getStagePosition());
         // Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start
         params.gravity = Gravity.LEFT;
@@ -277,10 +277,10 @@
             // Margin that insets the menuView inside the taskView
             float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
             setTranslationX(orientationHandler.getTaskMenuX(thumbnailAlignedX,
-                    mTaskContainer.getThumbnailViewDeprecated(), deviceProfile, taskInsetMargin,
+                    mTaskContainer.getSnapshotView(), deviceProfile, taskInsetMargin,
                     getIconView()));
             setTranslationY(orientationHandler.getTaskMenuY(
-                    thumbnailAlignedY, mTaskContainer.getThumbnailViewDeprecated(),
+                    thumbnailAlignedY, mTaskContainer.getSnapshotView(),
                     mTaskContainer.getStagePosition(), this, taskInsetMargin,
                     getIconView()));
         }
@@ -316,7 +316,7 @@
                 .createRevealAnimator(this, closing, revealAnimationStartProgress);
         mRevealAnimator.setInterpolator(enableOverviewIconMenu() ? Interpolators.EMPHASIZED
                 : Interpolators.DECELERATE);
-
+        AnimatorSet.Builder openCloseAnimatorBuilder = mOpenCloseAnimator.play(mRevealAnimator);
         if (enableOverviewIconMenu()) {
             IconAppChipView iconAppChip = (IconAppChipView) mTaskContainer.getIconView().asView();
 
@@ -334,11 +334,13 @@
                     closing ? mMenuTranslationYBeforeOpen
                             : mMenuTranslationYBeforeOpen + additionalTranslationY);
             translationYAnim.setInterpolator(EMPHASIZED);
+            openCloseAnimatorBuilder.with(translationYAnim);
 
             ObjectAnimator menuTranslationYAnim = ObjectAnimator.ofFloat(
                     iconAppChip.getMenuTranslationY(),
                     MULTI_PROPERTY_VALUE, closing ? 0 : additionalTranslationY);
             menuTranslationYAnim.setInterpolator(EMPHASIZED);
+            openCloseAnimatorBuilder.with(menuTranslationYAnim);
 
             float additionalTranslationX = 0;
             if (mContainer.getDeviceProfile().isLandscape
@@ -354,20 +356,15 @@
                     closing ? mMenuTranslationXBeforeOpen
                             : mMenuTranslationXBeforeOpen - additionalTranslationX);
             translationXAnim.setInterpolator(EMPHASIZED);
+            openCloseAnimatorBuilder.with(translationXAnim);
 
             ObjectAnimator menuTranslationXAnim = ObjectAnimator.ofFloat(
                     iconAppChip.getMenuTranslationX(),
                     MULTI_PROPERTY_VALUE, closing ? 0 : -additionalTranslationX);
             menuTranslationXAnim.setInterpolator(EMPHASIZED);
-
-            mOpenCloseAnimator.playTogether(translationYAnim, translationXAnim,
-                    menuTranslationXAnim, menuTranslationYAnim);
+            openCloseAnimatorBuilder.with(menuTranslationXAnim);
         }
-        mOpenCloseAnimator.playTogether(mRevealAnimator,
-                ObjectAnimator.ofFloat(
-                        mTaskContainer.getThumbnailViewDeprecated(), DIM_ALPHA,
-                        closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA),
-                ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
+        openCloseAnimatorBuilder.with(ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
         if (enableRefactorTaskThumbnail()) {
             mRevealAnimator.addUpdateListener(animation -> {
                 float animatedFraction = animation.getAnimatedFraction();
@@ -375,6 +372,10 @@
                 mTaskContainer.getTaskContainerData()
                         .getTaskMenuOpenProgress().setValue(openProgress);
             });
+        } else {
+            openCloseAnimatorBuilder.with(ObjectAnimator.ofFloat(
+                    mTaskContainer.getThumbnailViewDeprecated(), DIM_ALPHA,
+                    closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA));
         }
         mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
             @Override
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
index 4283d0e..2afb6a6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
@@ -99,36 +99,6 @@
                 }
             };
 
-    /** Use to animate thumbnail translationX while first app in split selection is initiated */
-    public static final Property<TaskThumbnailViewDeprecated, Float> SPLIT_SELECT_TRANSLATE_X =
-            new FloatProperty<TaskThumbnailViewDeprecated>("splitSelectTranslateX") {
-                @Override
-                public void setValue(TaskThumbnailViewDeprecated thumbnail,
-                        float splitSelectTranslateX) {
-                    thumbnail.applySplitSelectTranslateX(splitSelectTranslateX);
-                }
-
-                @Override
-                public Float get(TaskThumbnailViewDeprecated thumbnailView) {
-                    return thumbnailView.mSplitSelectTranslateX;
-                }
-            };
-
-    /** Use to animate thumbnail translationY while first app in split selection is initiated */
-    public static final Property<TaskThumbnailViewDeprecated, Float> SPLIT_SELECT_TRANSLATE_Y =
-            new FloatProperty<TaskThumbnailViewDeprecated>("splitSelectTranslateY") {
-                @Override
-                public void setValue(TaskThumbnailViewDeprecated thumbnail,
-                        float splitSelectTranslateY) {
-                    thumbnail.applySplitSelectTranslateY(splitSelectTranslateY);
-                }
-
-                @Override
-                public Float get(TaskThumbnailViewDeprecated thumbnailView) {
-                    return thumbnailView.mSplitSelectTranslateY;
-                }
-            };
-
     private final RecentsViewContainer mContainer;
     private TaskOverlay<?> mOverlay;
     private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -160,8 +130,6 @@
     private boolean mOverlayEnabled;
     /** Used as a placeholder when the original thumbnail animates out to. */
     private boolean mShowSplashForSplitSelection;
-    private float mSplitSelectTranslateX;
-    private float mSplitSelectTranslateY;
 
     public TaskThumbnailViewDeprecated(Context context) {
         this(context, null);
@@ -415,31 +383,6 @@
         }
     }
 
-    /** See {@link #SPLIT_SELECT_TRANSLATE_X} */
-    protected void applySplitSelectTranslateX(float splitSelectTranslateX) {
-        mSplitSelectTranslateX = splitSelectTranslateX;
-        applyTranslateX();
-    }
-
-    /** See {@link #SPLIT_SELECT_TRANSLATE_Y} */
-    protected void applySplitSelectTranslateY(float splitSelectTranslateY) {
-        mSplitSelectTranslateY = splitSelectTranslateY;
-        applyTranslateY();
-    }
-
-    private void applyTranslateX() {
-        setTranslationX(mSplitSelectTranslateX);
-    }
-
-    private void applyTranslateY() {
-        setTranslationY(mSplitSelectTranslateY);
-    }
-
-    protected void resetViewTransforms() {
-        mSplitSelectTranslateX = 0;
-        mSplitSelectTranslateY = 0;
-    }
-
     public TaskView getTaskView() {
         return (TaskView) getParent();
     }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 7a3b00f..d4b0040 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -23,7 +23,9 @@
 import android.app.ActivityOptions
 import android.content.Context
 import android.content.Intent
+import android.graphics.Bitmap
 import android.graphics.Canvas
+import android.graphics.Insets
 import android.graphics.PointF
 import android.graphics.Rect
 import android.graphics.drawable.Drawable
@@ -138,8 +140,8 @@
         /** Returns a copy of integer array containing taskIds of all tasks in the TaskView. */
         get() = taskContainers.map { it.task.key.id }.toIntArray()
 
-    val thumbnailViews: Array<TaskThumbnailViewDeprecated>
-        get() = taskContainers.map { it.thumbnailViewDeprecated }.toTypedArray()
+    val snapshotViews: Array<View>
+        get() = taskContainers.map { it.snapshotView }.toTypedArray()
 
     val isGridTask: Boolean
         /** Returns whether the task is part of overview grid and not being focused. */
@@ -171,6 +173,11 @@
         get() = taskContainers[0].thumbnailViewDeprecated
 
     @get:Deprecated("Use [taskContainers] instead.")
+    val firstSnapshotView: View
+        /** Returns the first snapshotView of the TaskView. */
+        get() = taskContainers[0].snapshotView
+
+    @get:Deprecated("Use [taskContainers] instead.")
     val firstItemInfo: ItemInfo
         get() = taskContainers[0].itemInfo
 
@@ -1197,10 +1204,10 @@
             this,
             container.task,
             container.iconView.drawable,
-            container.thumbnailViewDeprecated,
-            container.thumbnailViewDeprecated.thumbnail, /* intent */
-            null, /* user */
-            null,
+            container.snapshotView,
+            container.thumbnail,
+            /* intent */ null,
+            /* user */ null,
             container.itemInfo
         )
     }
@@ -1512,6 +1519,10 @@
         gridTranslationY = 0f
         boxTranslationY = 0f
         nonGridPivotTranslationX = 0f
+        taskContainers.forEach {
+            it.snapshotView.translationX = 0f
+            it.snapshotView.translationY = 0f
+        }
         resetViewTransforms()
     }
 
@@ -1537,10 +1548,6 @@
         alpha = stableAlpha
         setIconScaleAndDim(1f)
         setColorTint(0f, 0)
-        if (!enableRefactorTaskThumbnail()) {
-            // TODO(b/335399428) add split select functionality to new TTV
-            taskContainers.forEach { it.thumbnailViewDeprecated.resetViewTransforms() }
-        }
     }
 
     private fun getGridTrans(endTranslation: Float) =
@@ -1624,6 +1631,18 @@
         val snapshotView: View
             get() = thumbnailView ?: thumbnailViewDeprecated
 
+        // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
+        val thumbnail: Bitmap?
+            get() = thumbnailViewDeprecated.thumbnail
+
+        // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
+        val isRealSnapshot: Boolean
+            get() = thumbnailViewDeprecated.isRealSnapshot()
+
+        // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
+        val scaledInsets: Insets
+            get() = thumbnailViewDeprecated.scaledInsets
+
         /** Builds proto for logging */
         val itemInfo: WorkspaceItemInfo
             get() =
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index d40f8ab..c8893ad 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -33,7 +33,6 @@
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.quickstep.views.GroupedTaskView
 import com.android.quickstep.views.IconView
-import com.android.quickstep.views.TaskThumbnailViewDeprecated
 import com.android.quickstep.views.TaskView
 import com.android.quickstep.views.TaskView.TaskContainer
 import com.android.systemui.shared.recents.model.Task
@@ -59,7 +58,7 @@
     private val mockSplitSelectStateController: SplitSelectStateController = mock()
     // TaskView
     private val mockTaskView: TaskView = mock()
-    private val mockThumbnailView: TaskThumbnailViewDeprecated = mock()
+    private val mockSnapshotView: View = mock()
     private val mockBitmap: Bitmap = mock()
     private val mockIconView: IconView = mock()
     private val mockTaskViewDrawable: Drawable = mock()
@@ -87,8 +86,8 @@
 
     @Before
     fun setup() {
-        whenever(mockTaskContainer.thumbnailViewDeprecated).thenReturn(mockThumbnailView)
-        whenever(mockThumbnailView.thumbnail).thenReturn(mockBitmap)
+        whenever(mockTaskContainer.snapshotView).thenReturn(mockSnapshotView)
+        whenever(mockTaskContainer.thumbnail).thenReturn(mockBitmap)
         whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
         whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable)
         whenever(mockTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
@@ -180,7 +179,6 @@
 
         whenever(mockTaskContainer.task).thenReturn(mockTask)
         whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
-        whenever(mockTaskContainer.thumbnailViewDeprecated).thenReturn(mockThumbnailView)
         whenever(mockTask.getKey()).thenReturn(mockTaskKey)
         whenever(mockTaskKey.getId()).thenReturn(taskId)
         whenever(mockSplitSelectStateController.initialTaskId).thenReturn(taskId)
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index 03244eb..ce16b70 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -32,6 +32,8 @@
 
 import com.android.launcher3.util.LooperExecutor;
 import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.wm.shell.util.GroupedRecentTaskInfo;
 
 import org.junit.Before;
@@ -40,8 +42,11 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 @SmallTest
 public class RecentTasksListTest {
@@ -104,4 +109,52 @@
         assertEquals(taskDescription, taskList.get(0).task1.taskDescription.getLabel());
         assertNull(taskList.get(0).task2.taskDescription.getLabel());
     }
+
+    @Test
+    public void loadTasksInBackground_freeformTask_createsDesktopTask() {
+        ActivityManager.RecentTaskInfo[] tasks = {
+                createRecentTaskInfo(1 /* taskId */),
+                createRecentTaskInfo(4 /* taskId */),
+                createRecentTaskInfo(5 /* taskId */)};
+        GroupedRecentTaskInfo recentTaskInfos = GroupedRecentTaskInfo.forFreeformTasks(
+                tasks, Collections.emptySet() /* minimizedTaskIds */);
+        when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
+                .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
+
+        List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(
+                Integer.MAX_VALUE /* numTasks */, -1 /* requestId */, false /* loadKeysOnly */);
+
+        assertEquals(1, taskList.size());
+        assertEquals(TaskView.Type.DESKTOP, taskList.get(0).taskViewType);
+        List<Task> actualFreeformTasks = taskList.get(0).getTasks();
+        assertEquals(3, actualFreeformTasks.size());
+        assertEquals(1, actualFreeformTasks.get(0).key.id);
+        assertEquals(4, actualFreeformTasks.get(1).key.id);
+        assertEquals(5, actualFreeformTasks.get(2).key.id);
+    }
+
+    @Test
+    public void loadTasksInBackground_freeformTask_onlyMinimizedTasks_doesNotCreateDesktopTask() {
+        ActivityManager.RecentTaskInfo[] tasks = {
+                createRecentTaskInfo(1 /* taskId */),
+                createRecentTaskInfo(4 /* taskId */),
+                createRecentTaskInfo(5 /* taskId */)};
+        Set<Integer> minimizedTaskIds =
+                Arrays.stream(new Integer[]{1, 4, 5}).collect(Collectors.toSet());
+        GroupedRecentTaskInfo recentTaskInfos =
+                GroupedRecentTaskInfo.forFreeformTasks(tasks, minimizedTaskIds);
+        when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
+                .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
+
+        List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(
+                Integer.MAX_VALUE /* numTasks */, -1 /* requestId */, false /* loadKeysOnly */);
+
+        assertEquals(0, taskList.size());
+    }
+
+    private ActivityManager.RecentTaskInfo createRecentTaskInfo(int taskId) {
+        ActivityManager.RecentTaskInfo recentTaskInfo = new ActivityManager.RecentTaskInfo();
+        recentTaskInfo.taskId = taskId;
+        return recentTaskInfo;
+    }
 }
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index b39945b..27ce075 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -67,7 +67,7 @@
     <string name="widget_category_note_taking" msgid="3469689394504266039">"یادداشت‌برداری"</string>
     <string name="widget_add_button_label" msgid="2761267068711937179">"افزودن"</string>
     <string name="widget_add_button_content_description" msgid="1810530016360039643">"افزودن ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزارک، ضربه بزنید"</string>
+    <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزارک، تک‌ضرب بزنید"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"تغییر تنظیمات ابزارک"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"جستجوی برنامه‌ها"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"درحال بارگیری برنامه‌‌ها…"</string>
@@ -99,7 +99,7 @@
     <string name="permdesc_write_settings" msgid="726859348127868466">"به برنامه اجازه می‌دهد تنظیمات و میان‌برهای صفحه اصلی را تغییر دهد."</string>
     <string name="gadget_error_text" msgid="740356548025791839">"ابزارک را نمی‌توان بار کرد"</string>
     <string name="gadget_setup_text" msgid="8348374825537681407">"تنظیمات ابزارک"</string>
-    <string name="gadget_complete_setup_text" msgid="309040266978007925">"برای تکمیل راه‌اندازی ضربه بزنید"</string>
+    <string name="gadget_complete_setup_text" msgid="309040266978007925">"برای تکمیل راه‌اندازی تک‌ضرب بزنید"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"این برنامه سیستمی است و حذف نصب نمی‌شود."</string>
     <string name="folder_hint_text" msgid="5174843001373488816">"ویرایش نام"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> غیرفعال شد"</string>
@@ -108,8 +108,8 @@
     <string name="workspace_scroll_format" msgid="8458889198184077399">"‏صفحه اصلی %1$d از %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"صفحه اصلی جدید"</string>
     <string name="folder_opened" msgid="94695026776264709">"پوشه باز شده، <xliff:g id="WIDTH">%1$d</xliff:g> در <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
-    <string name="folder_tap_to_close" msgid="4625795376335528256">"برای بستن پوشه، ضربه بزنید"</string>
-    <string name="folder_tap_to_rename" msgid="4017685068016979677">"برای ذخیره تغییر نام، ضربه بزنید"</string>
+    <string name="folder_tap_to_close" msgid="4625795376335528256">"برای بستن پوشه، تک‌ضرب بزنید"</string>
+    <string name="folder_tap_to_rename" msgid="4017685068016979677">"برای ذخیره تغییر نام، تک‌ضرب بزنید"</string>
     <string name="folder_closed" msgid="4100806530910930934">"پوشه بسته شد"</string>
     <string name="folder_renamed" msgid="1794088362165669656">"نام پوشه به <xliff:g id="NAME">%1$s</xliff:g> تغییر کرد"</string>
     <string name="folder_name_format_exact" msgid="8626242716117004803">"پوشه: <xliff:g id="NAME">%1$s</xliff:g>، <xliff:g id="SIZE">%2$d</xliff:g> مورد"</string>
@@ -139,7 +139,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> درحال نصب است، <xliff:g id="PROGRESS">%2$s</xliff:g> تکمیل شده است"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"درحال بارگیری <xliff:g id="NAME">%1$s</xliff:g>، <xliff:g id="PROGRESS">%2$s</xliff:g> کامل شد"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> درانتظار نصب"</string>
-    <string name="app_archived_title" msgid="7717956158562544081">"<xliff:g id="NAME">%1$s</xliff:g> بایگانی شده است. برای بارگیری و بازیابی ضربه بزنید."</string>
+    <string name="app_archived_title" msgid="7717956158562544081">"<xliff:g id="NAME">%1$s</xliff:g> بایگانی شده است. برای بارگیری و بازیابی تک‌ضرب بزنید."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"برنامه باید به‌روز شود"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"برنامه برای این نماد به‌روز نشده است. می‌توانید آن را به‌صورت دستی به‌روز کنید تا میان‌بر دوباره فعال شود، یا نماد را بردارید."</string>
     <string name="dialog_update" msgid="2178028071796141234">"به‌روزرسانی"</string>
@@ -187,7 +187,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"فیلتر"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ناموفق بود: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"فضای خصوصی"</string>
-    <string name="private_space_secondary_label" msgid="9203933341714508907">"برای راه‌اندازی یا باز کردن، ضربه بزنید"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"برای راه‌اندازی یا باز کردن، تک‌ضرب بزنید"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"خصوصی"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"تنظیمات «فضای خصوصی»"</string>
     <string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"خصوصی، باز."</string>
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 1368084..c59e295 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -331,8 +331,21 @@
      * status bar, into account.
      */
     protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthUsed = getInsetsWidth();
+
         DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+        measureChildWithMargins(mContent, widthMeasureSpec,
+                widthUsed, heightMeasureSpec, deviceProfile.bottomSheetTopPadding);
+        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
+                MeasureSpec.getSize(heightMeasureSpec));
+    }
+
+    /**
+     * Returns the width used on left and right by the insets / padding.
+     */
+    protected int getInsetsWidth() {
         int widthUsed;
+        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         if (deviceProfile.isTablet) {
             widthUsed = Math.max(2 * getTabletHorizontalMargin(deviceProfile),
                     2 * (mInsets.left + mInsets.right));
@@ -343,11 +356,7 @@
             widthUsed = Math.max(padding.left + padding.right,
                     2 * (mInsets.left + mInsets.right));
         }
-
-        measureChildWithMargins(mContent, widthMeasureSpec,
-                widthUsed, heightMeasureSpec, deviceProfile.bottomSheetTopPadding);
-        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
-                MeasureSpec.getSize(heightMeasureSpec));
+        return widthUsed;
     }
 
     /** Returns the horizontal margins to be applied to the widget sheet. **/
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 9929892..fd15677 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -55,7 +55,6 @@
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -416,19 +415,18 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int availableWidth = MeasureSpec.getSize(widthMeasureSpec);
+        updateMaxSpansPerRow(availableWidth);
         doMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        if (updateMaxSpansPerRow()) {
-            doMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
     }
 
-    /** Returns {@code true} if the max spans have been updated. */
-    private boolean updateMaxSpansPerRow() {
-        if (getMeasuredWidth() == 0) return false;
-
-        @Px int maxHorizontalSpan = getContentView().getMeasuredWidth()
-                - (2 * mContentHorizontalMargin);
+    /** Returns {@code true} if the max spans have been updated.
+     *
+     * @param availableWidth Total width available within parent (includes insets).
+     */
+    private void updateMaxSpansPerRow(int availableWidth) {
+        @Px int maxHorizontalSpan = getAvailableWidthForSuggestions(
+                availableWidth - getInsetsWidth());
         if (mMaxSpanPerRow != maxHorizontalSpan) {
             mMaxSpanPerRow = maxHorizontalSpan;
             mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPxPerRow(
@@ -439,16 +437,15 @@
                 mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.setMaxHorizontalSpansPxPerRow(
                         maxHorizontalSpan);
             }
-            onRecommendedWidgetsBound();
-            return true;
+            post(this::onRecommendedWidgetsBound);
         }
-        return false;
     }
 
-    protected View getContentView() {
-        return mHasWorkProfile
-                ? mViewPager
-                : mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
+    /**
+     * Returns the width available to display suggestions.
+     */
+    protected int getAvailableWidthForSuggestions(int pickerAvailableWidth) {
+        return pickerAvailableWidth -  (2 * mContentHorizontalMargin);
     }
 
     @Override
@@ -493,7 +490,7 @@
                         .mWidgetsListAdapter.hasVisibleEntries());
         if (mIsNoWidgetsViewNeeded != isNoWidgetsViewNeeded) {
             mIsNoWidgetsViewNeeded = isNoWidgetsViewNeeded;
-            onRecommendedWidgetsBound();
+            post(this::onRecommendedWidgetsBound);
         }
     }
 
@@ -549,7 +546,7 @@
             mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
             // Visibility of recommended widgets, recycler views and headers are handled in methods
             // below.
-            onRecommendedWidgetsBound();
+            post(this::onRecommendedWidgetsBound);
             onWidgetsBound();
         }
     }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index ae8b5db..840d98a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -323,6 +323,30 @@
     }
 
     @Override
+    @Px
+    protected int getAvailableWidthForSuggestions(int pickerAvailableWidth) {
+        int rightPaneWidth = (int) Math.ceil(0.67 * pickerAvailableWidth);
+
+        if (mDeviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+            // See onLayout
+            int leftPaneWidth = (int) (0.33 * pickerAvailableWidth);
+            @Px int minLeftPaneWidthPx = Utilities.dpToPx(MINIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP);
+            @Px int maxLeftPaneWidthPx = Utilities.dpToPx(MAXIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP);
+            if (leftPaneWidth < minLeftPaneWidthPx) {
+                leftPaneWidth = minLeftPaneWidthPx;
+            } else if (leftPaneWidth > maxLeftPaneWidthPx) {
+                leftPaneWidth = maxLeftPaneWidthPx;
+            }
+            rightPaneWidth = pickerAvailableWidth - leftPaneWidth;
+        }
+
+        // Since suggestions are shown in right pane, the available width is 2/3 of total width of
+        // bottom sheet.
+        return rightPaneWidth - getResources().getDimensionPixelSize(
+                R.dimen.widget_list_horizontal_margin_two_pane); // right pane end margin.
+    }
+
+    @Override
     public void onActivePageChanged(int currentActivePage) {
         super.onActivePageChanged(currentActivePage);
 
@@ -384,11 +408,6 @@
 
     }
 
-    @Override
-    protected View getContentView() {
-        return mRightPane;
-    }
-
     private HeaderChangeListener getHeaderChangeListener() {
         return new HeaderChangeListener() {
             @Override