Merge "Handle long press directly if recents transition is deferred" into main
diff --git a/quickstep/res/layout/taskbar_divider_popup_menu.xml b/quickstep/res/layout/taskbar_divider_popup_menu.xml
index 4348a47..6fbb586 100644
--- a/quickstep/res/layout/taskbar_divider_popup_menu.xml
+++ b/quickstep/res/layout/taskbar_divider_popup_menu.xml
@@ -38,6 +38,7 @@
         android:theme="@style/PopupItem">
 
         <View
+            android:id="@+id/taskbar_pinning_visibility_icon"
             android:layout_margin="6dp"
             android:layout_width="20dp"
             android:layout_height="20dp"
@@ -45,13 +46,17 @@
             android:backgroundTint="?android:attr/textColorPrimary" />
 
         <Switch
-            style="@style/BaseIcon"
+            style="@style/Switch.SettingsLib"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:id="@+id/taskbar_pinning_switch"
             android:background="@null"
             android:clickable="false"
             android:gravity="start|center_vertical"
             android:textAlignment="viewStart"
             android:paddingStart="12dp"
+            android:layout_weight="1"
+            android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
             android:singleLine="true"
             android:ellipsize="end"
             android:textSize="14sp"
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index aaa699b..22f98fa 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -386,6 +386,7 @@
 
     <!--- Taskbar Pinning -->
     <dimen name="taskbar_pinning_popup_menu_width">300dp</dimen>
+    <dimen name="taskbar_pinning_popup_menu_vertical_margin">16dp</dimen>
 
     <!-- Recents overview -->
     <dimen name="recents_filter_icon_size">30dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index d13b53f..3f9b66a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -15,22 +15,29 @@
  */
 package com.android.launcher3.taskbar
 
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
 import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.Rect
 import android.graphics.drawable.GradientDrawable
 import android.util.AttributeSet
+import android.util.Property
 import android.view.Gravity
 import android.view.MotionEvent
 import android.view.View
 import android.widget.LinearLayout
 import android.widget.Switch
 import androidx.core.view.postDelayed
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
 import com.android.launcher3.R
 import com.android.launcher3.popup.ArrowPopup
 import com.android.launcher3.popup.RoundedArrowDrawable
 import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.Themes
+import com.android.launcher3.views.ActivityContext
 
 /** Popup view with arrow for taskbar pinning */
 class TaskbarDividerPopupView<T : TaskbarActivityContext>
@@ -42,7 +49,8 @@
 ) : ArrowPopup<T>(context, attrs, defStyleAttr) {
     companion object {
         private const val TAG = "TaskbarDividerPopupView"
-        private const val DIVIDER_POPUP_CLOSING_DELAY = 500L
+        private const val DIVIDER_POPUP_CLOSING_DELAY = 333L
+        private const val DIVIDER_POPUP_CLOSING_ANIMATION_DURATION = 83L
 
         @JvmStatic
         fun createAndPopulate(
@@ -63,7 +71,7 @@
     private lateinit var dividerView: View
 
     private val menuWidth =
-        context.resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_width)
+        resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_width)
     private val popupCornerRadius = Themes.getDialogCornerRadius(context)
     private val arrowWidth = resources.getDimension(R.dimen.popup_arrow_width)
     private val arrowHeight = resources.getDimension(R.dimen.popup_arrow_height)
@@ -71,6 +79,8 @@
 
     private var alwaysShowTaskbarOn = !DisplayController.isTransientTaskbar(context)
     private var didPreferenceChange = false
+    private var verticalOffsetForPopupView =
+        resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_vertical_margin)
 
     /** Callback invoked when the pinning popup view is closing. */
     var onCloseCallback: (preferenceChanged: Boolean) -> Unit = {}
@@ -94,11 +104,22 @@
         super.onFinishInflate()
         val taskbarSwitchOption = requireViewById<LinearLayout>(R.id.taskbar_switch_option)
         val alwaysShowTaskbarSwitch = requireViewById<Switch>(R.id.taskbar_pinning_switch)
+        val taskbarVisibilityIcon = requireViewById<View>(R.id.taskbar_pinning_visibility_icon)
         alwaysShowTaskbarSwitch.isChecked = alwaysShowTaskbarOn
-        taskbarSwitchOption.setOnClickListener {
-            alwaysShowTaskbarSwitch.isClickable = true
-            alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn
-            onClickAlwaysShowTaskbarSwitchOption()
+        if (ActivityContext.lookupContext<TaskbarActivityContext>(context).isGestureNav) {
+            taskbarSwitchOption.setOnClickListener {
+                alwaysShowTaskbarSwitch.isClickable = true
+                alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn
+                onClickAlwaysShowTaskbarSwitchOption()
+            }
+        } else {
+            alwaysShowTaskbarSwitch.isEnabled = false
+        }
+
+        if (!alwaysShowTaskbarSwitch.isEnabled) {
+            taskbarVisibilityIcon.background.setTint(
+                resources.getColor(android.R.color.system_neutral2_500, context.theme)
+            )
         }
     }
 
@@ -171,10 +192,71 @@
         }
     }
 
-    override fun closeComplete() {
+    override fun getExtraVerticalOffset(): Int {
+        return (mActivityContext.deviceProfile.taskbarHeight -
+            mActivityContext.deviceProfile.taskbarIconSize) / 2 + verticalOffsetForPopupView
+    }
+
+    override fun animateClose() {
+        if (!mIsOpen) {
+            return
+        }
+        if (mOpenCloseAnimator != null) {
+            mOpenCloseAnimator.cancel()
+        }
+        mIsOpen = false
+
+        mOpenCloseAnimator = getCloseAnimator()
+
+        mOpenCloseAnimator.addListener(
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationEnd(animation: Animator) {
+                    mOpenCloseAnimator = null
+                    if (mDeferContainerRemoval) {
+                        setVisibility(INVISIBLE)
+                    } else {
+                        closeComplete()
+                    }
+                }
+            }
+        )
         onCloseCallback(didPreferenceChange)
         onCloseCallback = {}
-        super.closeComplete()
+        mOpenCloseAnimator.start()
+    }
+
+    private fun getCloseAnimator(): AnimatorSet {
+        val alphaValues = floatArrayOf(1f, 0f)
+        val translateYValue =
+            if (!alwaysShowTaskbarOn) verticalOffsetForPopupView else -verticalOffsetForPopupView
+        val alpha = getAnimatorOfFloat(this, ALPHA, *alphaValues)
+        val arrowAlpha = getAnimatorOfFloat(mArrow, ALPHA, *alphaValues)
+        val translateY =
+            ObjectAnimator.ofFloat(
+                this,
+                TRANSLATION_Y,
+                *floatArrayOf(this.translationY, this.translationY + translateYValue)
+            )
+        val arrowTranslateY =
+            ObjectAnimator.ofFloat(
+                mArrow,
+                TRANSLATION_Y,
+                *floatArrayOf(mArrow.translationY, mArrow.translationY + translateYValue)
+            )
+        val animatorSet = AnimatorSet()
+        animatorSet.playTogether(alpha, arrowAlpha, translateY, arrowTranslateY)
+        return animatorSet
+    }
+
+    private fun getAnimatorOfFloat(
+        view: View,
+        property: Property<View, Float>,
+        vararg values: Float
+    ): Animator {
+        val animator: Animator = ObjectAnimator.ofFloat(view, property, *values)
+        animator.setDuration(DIVIDER_POPUP_CLOSING_ANIMATION_DURATION)
+        animator.interpolator = EMPHASIZED_ACCELERATE
+        return animator
     }
 
     private fun onClickAlwaysShowTaskbarSwitchOption() {
@@ -182,7 +264,7 @@
         // Allow switch animation to finish and then close the popup.
         postDelayed(DIVIDER_POPUP_CLOSING_DELAY) {
             if (isOpen) {
-                close(false)
+                close(true)
             }
         }
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index d1bed3e..cbfa024 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -82,9 +82,12 @@
             taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue)
         )
 
+        controllers.taskbarOverlayController.hideWindow()
+
         animatorSet.doOnEnd { recreateTaskbarAndUpdatePinningValue() }
         animatorSet.duration = PINNING_ANIMATION_DURATION
         updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true)
+        taskbarViewController.animateAwayNotificationDotsDuringTaskbarPinningAnimation()
         animatorSet.start()
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index fd66b45..78d5bd3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -52,6 +52,7 @@
 import androidx.core.view.OneShotPreDrawListener;
 
 import com.android.app.animation.Interpolators;
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
@@ -338,6 +339,17 @@
         }
     }
 
+    /**
+     * Animate away taskbar icon notification dots during the taskbar pinning animation.
+     */
+    public void animateAwayNotificationDotsDuringTaskbarPinningAnimation() {
+        for (View iconView : mTaskbarView.getIconViews()) {
+            if (iconView instanceof BubbleTextView && ((BubbleTextView) iconView).hasDot()) {
+                ((BubbleTextView) iconView).animateDotScale(0);
+            }
+        }
+    }
+
     private void updateTaskbarIconTranslationXForPinning() {
         View[] iconViews = mTaskbarView.getIconViews();
         float scale = mTaskbarIconTranslationXForPinning.value;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
index 6279f63..28d4bf8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
@@ -57,6 +57,7 @@
     public static final String NAMESPACE_LAUNCHER = "launcher";
 
     private static final List<DebugFlag> sDebugFlags = new ArrayList<>();
+    private static final List<IntFlag> sIntFlags = new ArrayList<>();
     private static SharedPreferences sSharedPreferences;
 
     static final BooleanFlag TEAMFOOD_FLAG = getReleaseFlag(
@@ -132,7 +133,14 @@
     public static IntFlag getIntFlag(
             int bugId, String key, int defaultValueInCode, String description) {
         INSTANCE.mKeySet.add(key);
-        return new IntFlag(DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, defaultValueInCode));
+        int defaultValue = DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, defaultValueInCode);
+        if (IS_DEBUG_DEVICE) {
+            IntDeviceFlag flag = new IntDeviceFlag(key, defaultValue, defaultValueInCode);
+            sIntFlags.add(flag);
+            return flag;
+        } else {
+            return new IntFlag(defaultValue);
+        }
     }
 
     static List<DebugFlag> getDebugFlags() {
@@ -163,13 +171,20 @@
             return;
         }
         pw.println("DeviceFlags:");
+        pw.println("  BooleanFlags:");
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
                 if (flag instanceof DeviceFlag) {
-                    pw.println("  " + flag);
+                    pw.println("    " + flag);
                 }
             }
         }
+        pw.println("  IntFlags:");
+        synchronized (sIntFlags) {
+            for (IntFlag flag : sIntFlags) {
+                pw.println("    " + flag);
+            }
+        }
         pw.println("DebugFlags:");
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/IntDeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/IntDeviceFlag.java
new file mode 100644
index 0000000..4f3b0ae
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/IntDeviceFlag.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides.flags;
+
+import com.android.launcher3.config.FeatureFlags.IntFlag;
+
+public class IntDeviceFlag extends IntFlag {
+    public final String key;
+    private final int mDefaultValueInCode;
+
+    public IntDeviceFlag(String key, int currentValue, int defaultValueInCode) {
+        super(currentValue);
+        this.key = key;
+        mDefaultValueInCode = defaultValueInCode;
+    }
+
+    @Override
+    public String toString() {
+        return key + ": mCurrentValue=" + get() + ", defaultValueInCode=" + mDefaultValueInCode;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 8d26fd4..db5ad82 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -23,9 +23,9 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
 import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS;
-import static com.android.launcher3.util.NavigationMode.TWO_BUTTONS;
 import static com.android.launcher3.util.SettingsCache.ONE_HANDED_ENABLED;
 import static com.android.launcher3.util.SettingsCache.ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
@@ -55,8 +55,11 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.provider.Settings;
+import android.util.Log;
+import android.view.ISystemGestureExclusionListener;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
+import android.view.WindowManagerGlobal;
 
 import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
@@ -74,7 +77,6 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
-import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 
@@ -86,6 +88,8 @@
  */
 public class RecentsAnimationDeviceState implements DisplayInfoChangeListener {
 
+    private static final String TAG = "RecentsAnimationDeviceState";
+
     static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
 
     // TODO: Move to quickstep contract
@@ -95,6 +99,23 @@
     private final Context mContext;
     private final DisplayController mDisplayController;
     private final int mDisplayId;
+
+    private final ISystemGestureExclusionListener mGestureExclusionListener =
+            new ISystemGestureExclusionListener.Stub() {
+                @BinderThread
+                @Override
+                public void onSystemGestureExclusionChanged(int displayId,
+                        Region systemGestureExclusionRegion, Region unrestrictedOrNull) {
+                    if (displayId != mDisplayId) {
+                        return;
+                    }
+                    // Assignments are atomic, it should be safe on binder thread. Also we don't
+                    // think systemGestureExclusionRegion can be null but just in case, don't let
+                    // mExclusionRegion be null.
+                    mExclusionRegion = systemGestureExclusionRegion != null
+                            ? systemGestureExclusionRegion : new Region();
+                }
+            };
     private final RotationTouchHelper mRotationTouchHelper;
     private final TaskStackChangeListener mPipListener;
     // Cache for better performance since it doesn't change at runtime.
@@ -118,7 +139,7 @@
 
     private int mGestureBlockingTaskId = -1;
     private @NonNull Region mExclusionRegion = new Region();
-    private SystemGestureExclusionListenerCompat mExclusionListener;
+    private boolean mExclusionListenerRegistered;
 
     public RecentsAnimationDeviceState(Context context) {
         this(context, false);
@@ -142,19 +163,7 @@
         }
 
         // Register for exclusion updates
-        mExclusionListener = new SystemGestureExclusionListenerCompat(mDisplayId) {
-            @Override
-            @BinderThread
-            public void onExclusionChanged(Region region) {
-                if (region == null) {
-                    // Don't think this is possible but just in case, don't let it be null.
-                    region = new Region();
-                }
-                // Assignments are atomic, it should be safe on binder thread
-                mExclusionRegion = region;
-            }
-        };
-        runOnDestroy(mExclusionListener::unregister);
+        runOnDestroy(() -> unregisterExclusionListener());
 
         // Register for display changes changes
         mDisplayController.addChangeListener(this);
@@ -247,13 +256,54 @@
             mNavBarPosition = new NavBarPosition(mMode, info);
 
             if (mMode == NO_BUTTON) {
-                mExclusionListener.register();
+                registerExclusionListener();
             } else {
-                mExclusionListener.unregister();
+                unregisterExclusionListener();
             }
         }
     }
 
+    /**
+     * Registers {@link mGestureExclusionListener} for getting exclusion rect changes. Note that we
+     * make binder call on {@link UI_HELPER_EXECUTOR} to avoid jank.
+     */
+    public void registerExclusionListener() {
+        UI_HELPER_EXECUTOR.execute(() -> {
+            if (mExclusionListenerRegistered) {
+                return;
+            }
+            try {
+                WindowManagerGlobal.getWindowManagerService()
+                        .registerSystemGestureExclusionListener(
+                                mGestureExclusionListener, mDisplayId);
+                mExclusionListenerRegistered = true;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to register window manager callbacks", e);
+            }
+        });
+    }
+
+    /**
+     * Unregisters {@link mGestureExclusionListener} if previously registered. We make binder call
+     * on same {@link UI_HELPER_EXECUTOR} as in {@link #registerExclusionListener()} so that
+     * read/write {@link mExclusionListenerRegistered} field is thread safe.
+     */
+    public void unregisterExclusionListener() {
+        UI_HELPER_EXECUTOR.execute(() -> {
+            if (!mExclusionListenerRegistered) {
+                return;
+            }
+            try {
+                WindowManagerGlobal.getWindowManagerService()
+                        .unregisterSystemGestureExclusionListener(
+                                mGestureExclusionListener, mDisplayId);
+                mExclusionListenerRegistered = false;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to unregister window manager callbacks", e);
+            }
+        });
+    }
+
     public void onOneHandedModeChanged(int newGesturalHeight) {
         mRotationTouchHelper.setGesturalHeight(newGesturalHeight);
     }
@@ -280,13 +330,6 @@
     }
 
     /**
-     * @return whether the current nav mode is 2-button-based.
-     */
-    public boolean isTwoButtonNavMode() {
-        return mMode == TWO_BUTTONS;
-    }
-
-    /**
      * @return whether the current nav mode is button-based.
      */
     public boolean isButtonNavMode() {
@@ -391,13 +434,6 @@
     }
 
     /**
-     * @return whether notification panel is expanded
-     */
-    public boolean isNotificationPanelExpanded() {
-        return (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0;
-    }
-
-    /**
      * @return whether the global actions dialog is showing
      */
     public boolean isSystemUiDialogShowing() {
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 5147538..00d8008 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -17,7 +17,6 @@
 
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
 
-import static com.android.launcher3.testing.shared.TestProtocol.SPLIT_LEAK;
 import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -99,6 +98,7 @@
 import com.android.wm.shell.transition.IShellTransitions;
 import com.android.wm.shell.util.GroupedRecentTaskInfo;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashMap;
@@ -272,7 +272,6 @@
      */
     @MainThread
     public void clearProxy() {
-        testLogD(SPLIT_LEAK, "systemUiProxy clearingProxy");
         setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null);
     }
 
@@ -401,6 +400,17 @@
     }
 
     @Override
+    public void animateNavBarLongPress(boolean isTouchDown, long durationMs) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.animateNavBarLongPress(isTouchDown, durationMs);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call animateNavBarLongPress", e);
+            }
+        }
+    }
+
+    @Override
     public void notifyAccessibilityButtonClicked(int displayId) {
         if (mSystemUiProxy != null) {
             try {
@@ -1252,19 +1262,21 @@
     }
 
     public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
-        if (mRecentTasks != null) {
-            try {
-                final GroupedRecentTaskInfo[] rawTasks = mRecentTasks.getRecentTasks(numTasks,
-                        RECENT_IGNORE_UNAVAILABLE, userId);
-                if (rawTasks == null) {
-                    return new ArrayList<>();
-                }
-                return new ArrayList<>(Arrays.asList(rawTasks));
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed call getRecentTasks", e);
-            }
+        if (mRecentTasks == null) {
+            Log.w(TAG, "getRecentTasks() failed due to null mRecentTasks");
+            return new ArrayList<>();
         }
-        return new ArrayList<>();
+        try {
+            final GroupedRecentTaskInfo[] rawTasks = mRecentTasks.getRecentTasks(numTasks,
+                    RECENT_IGNORE_UNAVAILABLE, userId);
+            if (rawTasks == null) {
+                return new ArrayList<>();
+            }
+            return new ArrayList<>(Arrays.asList(rawTasks));
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed call getRecentTasks", e);
+            return new ArrayList<>();
+        }
     }
 
     /**
@@ -1408,7 +1420,7 @@
     public boolean startRecentsActivity(Intent intent, ActivityOptions options,
             RecentsAnimationListener listener) {
         if (mRecentTasks == null) {
-            ActiveGestureLog.INSTANCE.trackEvent(RECENT_TASKS_MISSING);
+            ActiveGestureLog.INSTANCE.addLog("Null mRecentTasks", RECENT_TASKS_MISSING);
             return false;
         }
         final IRecentsAnimationRunner runner = new IRecentsAnimationRunner.Stub() {
@@ -1466,4 +1478,35 @@
             return false;
         }
     }
+
+    public void dump(PrintWriter pw) {
+        pw.println(TAG + ":");
+
+        pw.println("\tmSystemUiProxy=" + mSystemUiProxy);
+        pw.println("\tmPip=" + mPip);
+        pw.println("\tmPipAnimationListener=" + mPipAnimationListener);
+        pw.println("\tmBubbles=" + mBubbles);
+        pw.println("\tmBubblesListener=" + mBubblesListener);
+        pw.println("\tmSplitScreen=" + mSplitScreen);
+        pw.println("\tmSplitScreenListener=" + mSplitScreenListener);
+        pw.println("\tmSplitSelectListener=" + mSplitSelectListener);
+        pw.println("\tmOneHanded=" + mOneHanded);
+        pw.println("\tmShellTransitions=" + mShellTransitions);
+        pw.println("\tmHomeTransitionListener=" + mHomeTransitionListener);
+        pw.println("\tmStartingWindow=" + mStartingWindow);
+        pw.println("\tmStartingWindowListener=" + mStartingWindowListener);
+        pw.println("\tmSysuiUnlockAnimationController=" + mSysuiUnlockAnimationController);
+        pw.println("\tmLauncherActivityClass=" + mLauncherActivityClass);
+        pw.println("\tmLauncherUnlockAnimationController=" + mLauncherUnlockAnimationController);
+        pw.println("\tmRecentTasks=" + mRecentTasks);
+        pw.println("\tmRecentTasksListener=" + mRecentTasksListener);
+        pw.println("\tmBackAnimation=" + mBackAnimation);
+        pw.println("\tmBackToLauncherCallback=" + mBackToLauncherCallback);
+        pw.println("\tmBackToLauncherRunner=" + mBackToLauncherRunner);
+        pw.println("\tmDesktopMode=" + mDesktopMode);
+        pw.println("\tmDesktopTaskListener=" + mDesktopTaskListener);
+        pw.println("\tmUnfoldAnimation=" + mUnfoldAnimation);
+        pw.println("\tmUnfoldAnimationListener=" + mUnfoldAnimationListener);
+        pw.println("\tmDragAndDrop=" + mDragAndDrop);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 662a895..3d8191d 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -693,15 +693,17 @@
             launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE);
             launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
 
-            windowAnimEndListener = new AnimatorListenerAdapter() {
+            windowAnimEndListener = new AnimationSuccessListener() {
                 @Override
                 public void onAnimationStart(Animator animation) {
                     recentsView.onTaskLaunchedInLiveTileMode();
                 }
 
                 // Make sure recents gets fixed up by resetting task alphas and scales, etc.
+                // This should only be run onAnimationSuccess, otherwise finishRecentsAnimation will
+                // interfere with a rapid swipe up to home in the live tile + running task case.
                 @Override
-                public void onAnimationEnd(Animator animation) {
+                public void onAnimationSuccess(Animator animation) {
                     recentsView.finishRecentsAnimation(false /* toRecents */, () -> {
                         recentsView.post(() -> {
                             stateManager.moveToRestState();
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 7399c31..b4fe5e4 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -1374,6 +1374,7 @@
         mTaskbarManager.dumpLogs("", pw);
         pw.println("AssistStateManager:");
         AssistStateManager.INSTANCE.get(this).dump("  ", pw);
+        SystemUiProxy.INSTANCE.get(this).dump(pw);
     }
 
     private AbsSwipeUpHandler createLauncherSwipeHandler(
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index efa84d3..d38376c 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -38,7 +38,6 @@
     private final NavHandleLongPressHandler mNavHandleLongPressHandler;
     private final float mNavHandleWidth;
     private final float mScreenWidth;
-    private final ViewConfiguration mViewConfiguration;
 
     private final Runnable mTriggerLongPress = this::triggerLongPress;
     private final float mTouchSlopSquared;
@@ -49,7 +48,6 @@
     public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
             InputMonitorCompat inputMonitor, RecentsAnimationDeviceState deviceState) {
         super(delegate, inputMonitor);
-        mViewConfiguration = ViewConfiguration.get(context);
         mNavHandleWidth = context.getResources().getDimensionPixelSize(
                 R.dimen.navigation_home_handle_width);
         mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
@@ -69,6 +67,18 @@
 
     @Override
     public void onMotionEvent(MotionEvent ev) {
+        if (mDelegate.allowInterceptByParent()) {
+            handleMotionEvent(ev);
+        } else if (MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)) {
+            cancelLongPress();
+        }
+
+        if (mState != STATE_ACTIVE) {
+            mDelegate.onMotionEvent(ev);
+        }
+    }
+
+    private void handleMotionEvent(MotionEvent ev) {
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN -> {
                 if (mCurrentDownEvent != null) {
@@ -103,10 +113,6 @@
             MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
             MAIN_EXECUTOR.getHandler().post(mTriggerLongPress);
         }
-
-        if (mState != STATE_ACTIVE) {
-            mDelegate.onMotionEvent(ev);
-        }
     }
 
     private void triggerLongPress() {
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 1f6dae6..fce188f 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -15,6 +15,9 @@
  */
 package com.android.quickstep.interaction;
 
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+
 import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.Utilities.mapBoundToRange;
@@ -47,6 +50,8 @@
 import android.util.Log;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
+import android.view.Window;
+import android.view.WindowInsetsController;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.widget.ImageView;
@@ -122,6 +127,17 @@
         Resources resources = getResources();
         int mode = resources.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
         boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES;
+
+        int systemBarsMask = APPEARANCE_LIGHT_STATUS_BARS | APPEARANCE_LIGHT_NAVIGATION_BARS;
+        int systemBarsAppearance = isDarkTheme ? 0 : systemBarsMask;
+        Window window = getWindow();
+        WindowInsetsController insetsController = window == null
+                ? null
+                : window.getInsetsController();
+        if (insetsController != null) {
+            insetsController.setSystemBarsAppearance(systemBarsAppearance, systemBarsMask);
+        }
+
         Intent intent = getIntent();
         int accentColor = intent.getIntExtra(
                 isDarkTheme ? EXTRA_ACCENT_COLOR_DARK_MODE : EXTRA_ACCENT_COLOR_LIGHT_MODE,
@@ -300,7 +316,9 @@
         if (mBackgroundAnimatorListener != null) {
             mAnimatedBackground.removeAnimatorListener(mBackgroundAnimatorListener);
         }
-        dispatchLauncherAnimStartEnd();
+        if (!isChangingConfigurations()) {
+            dispatchLauncherAnimStartEnd();
+        }
     }
 
     private AnimatedFloat createSwipeUpProxy(GestureState state) {
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 16235e0..12568ea 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -162,6 +162,7 @@
     @Before
     public void setUp() {
         mLauncher.onTestStart();
+        AbstractLauncherUiTest.waitForSetupWizardDismissal();
         AbstractLauncherUiTest.verifyKeyguardInvisible();
     }
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index f6368b0..f51f286 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -92,7 +92,7 @@
         startTestActivity(2);
         startTestActivity(3);
 
-        if (mLauncher.isTablet()) {
+        if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
             mLauncher.goHome().switchToOverview().getOverviewActions()
                     .clickSplit()
                     .getTestActivityTask(2)
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index d45c225..4075c55 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -179,6 +179,8 @@
     @PortraitLandscape
     @PlatinumTest(focusArea = "launcher")
     public void testOverviewActions() throws Exception {
+        assumeFalse("Skipping Overview Actions tests for grid only overview",
+                mLauncher.isTablet() && mLauncher.isGridOnlyOverviewEnabled());
         // Experimenting for b/165029151:
         final Overview overview = mLauncher.goHome().switchToOverview();
         if (overview.hasTasks()) overview.dismissAllTasks();
@@ -334,7 +336,6 @@
     @Test
     @PortraitLandscape
     @NavigationModeSwitch
-    @PlatinumTest(focusArea = "launcher")
     public void testPressBack() throws Exception {
         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
                 READ_DEVICE_CONFIG_PERMISSION);
@@ -377,7 +378,9 @@
         // Test opening the task.
         overview.getCurrentTask().open();
         assertTrue("Test activity didn't open from Overview",
-                mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity10")),
+                mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()).text(
+                                mLauncher.isGridOnlyOverviewEnabled() ? "TestActivity12"
+                                        : "TestActivity13")),
                         DEFAULT_UI_TIMEOUT));
 
         // Scroll the task offscreen as it is now first
@@ -398,16 +401,17 @@
                 (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
                         launcher)) <= 1)));
 
-        // Test dismissing more tasks.
-        assertTrue("Launcher internal state didn't remain in Overview",
-                isInState(() -> LauncherState.OVERVIEW));
-        overview.getCurrentTask().dismiss();
-        assertTrue("Launcher internal state didn't remain in Overview",
-                isInState(() -> LauncherState.OVERVIEW));
-        overview.getCurrentTask().dismiss();
-        executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals",
-                (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
-                        launcher)) <= 1)));
+        // TODO(b/308841019): Re-enable after fixing Overview jank when dismiss
+//        // Test dismissing more tasks.
+//        assertTrue("Launcher internal state didn't remain in Overview",
+//                isInState(() -> LauncherState.OVERVIEW));
+//        overview.getCurrentTask().dismiss();
+//        assertTrue("Launcher internal state didn't remain in Overview",
+//                isInState(() -> LauncherState.OVERVIEW));
+//        overview.getCurrentTask().dismiss();
+//        executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals",
+//                (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
+//                        launcher)) <= 1)));
 
         // Test dismissing all tasks.
         mLauncher.goHome().switchToOverview().dismissAllTasks();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index acbb58f..ee0fbb8 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -143,7 +143,7 @@
         startTestActivity(2);
         startTestActivity(3);
 
-        if (mLauncher.isTablet()) {
+        if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) {
             mLauncher.goHome().switchToOverview().getOverviewActions()
                     .clickSplit()
                     .getTestActivityTask(2)
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 39f1477..138e1b3 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -133,7 +133,7 @@
     <string name="widgets_list_closed" msgid="6141506579418771922">"ವಿಜೆಟ್ ಪಟ್ಟಿಯನ್ನು ಮುಚ್ಚಲಾಗಿದೆ"</string>
     <string name="action_add_to_workspace" msgid="215894119683164916">"ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಸೇರಿಸಿ"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ಐಟಂ ಇಲ್ಲಿಗೆ ಸರಿಸಿ"</string>
-    <string name="item_added_to_workspace" msgid="4211073925752213539">"ಮುಖಪುಟ ಪರದೆಗೆ ಐಟಂ ಸೇರಿಸಲಾಗಿದೆ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಐಟಂ ಸೇರಿಸಲಾಗಿದೆ"</string>
     <string name="item_removed" msgid="851119963877842327">"ಐಟಂ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
     <string name="undo" msgid="4151576204245173321">"ರದ್ದುಮಾಡಿ"</string>
     <string name="action_move" msgid="4339390619886385032">"ಐಟಂ ಸರಿಸಿ"</string>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 883c379..e2e528c 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -22,7 +22,6 @@
 import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING;
 import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
 import static com.android.launcher3.icons.BitmapInfo.FLAG_NO_BADGE;
-import static com.android.launcher3.icons.BitmapInfo.FLAG_SKIP_USER_BADGE;
 import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
@@ -165,8 +164,6 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mHideBadge = false;
     @ViewDebug.ExportedProperty(category = "launcher")
-    private boolean mSkipUserBadge = false;
-    @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mIsIconVisible = true;
     @ViewDebug.ExportedProperty(category = "launcher")
     private int mTextColor;
@@ -269,10 +266,6 @@
         mHideBadge = hideBadge;
     }
 
-    public void setSkipUserBadge(boolean skipUserBadge) {
-        mSkipUserBadge = skipUserBadge;
-    }
-
     /**
      * Resets the view so it can be recycled.
      */
@@ -301,7 +294,7 @@
         }
     }
 
-    private void animateDotScale(float... dotScales) {
+    public void animateDotScale(float... dotScales) {
         cancelDotScaleAnim();
         mDotScaleAnim = ObjectAnimator.ofFloat(this, DOT_SCALE_PROPERTY, dotScales);
         mDotScaleAnim.addListener(new AnimatorListenerAdapter() {
@@ -402,9 +395,6 @@
         if (mHideBadge || mDisplay == DISPLAY_SEARCH_RESULT_SMALL) {
             flags |= FLAG_NO_BADGE;
         }
-        if (mSkipUserBadge) {
-            flags |= FLAG_SKIP_USER_BADGE;
-        }
         FastBitmapDrawable iconDrawable = info.newIcon(getContext(), flags);
         mDotParams.appColor = iconDrawable.getIconColor();
         mDotParams.dotColor = Themes.getAttrColor(getContext(), R.attr.notificationDotColor);
@@ -656,7 +646,7 @@
         return mForceHideDot;
     }
 
-    private boolean hasDot() {
+    public boolean hasDot() {
         return mDotInfo != null;
     }
 
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index 8ec5c18..8ff030e 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -101,8 +101,14 @@
     }
 
     public void hideKeyboard() {
+        hideKeyboard(/* clearFocus= */ true);
+    }
+
+    public void hideKeyboard(boolean clearFocus) {
         ActivityContext.lookupContext(getContext()).hideKeyboard();
-        clearFocus();
+        if (clearFocus) {
+            clearFocus();
+        }
     }
 
     protected void onKeyboardShown() {
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 4f8caab..aa06089 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -334,21 +334,21 @@
         val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT =
                 nonRestorableItem(
                         "pref_long_press_nav_handle_haptic_hint_end_scale_percent",
-                        50,
+                        100,
                         EncryptionType.MOVE_TO_DEVICE_PROTECTED
                 )
         @JvmField
         val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT =
                 nonRestorableItem(
                         "pref_long_press_nav_handle_haptic_hint_scale_exponent",
-                        2,
+                        1,
                         EncryptionType.MOVE_TO_DEVICE_PROTECTED
                 )
         @JvmField
         val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS =
                 nonRestorableItem(
                         "pref_long_press_nav_handle_haptic_hint_iterations",
-                        40,
+                        50,
                         EncryptionType.MOVE_TO_DEVICE_PROTECTED
                 )
         @JvmField
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 84d3805..2315111 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -49,6 +49,7 @@
 import android.animation.ValueAnimator;
 import android.util.FloatProperty;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.LauncherState.PageAlphaProvider;
@@ -164,6 +165,8 @@
                 state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE)
                         ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                         : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+        hotseat.setDescendantFocusability(state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE)
+                ? ViewGroup.FOCUS_BLOCK_DESCENDANTS : ViewGroup.FOCUS_BEFORE_DESCENDANTS);
 
         Interpolator translationInterpolator =
                 config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 005e6df..7baf7d3 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -27,7 +27,6 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.Flags;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
 import com.android.launcher3.config.FeatureFlags;
@@ -213,6 +212,7 @@
                 BubbleTextView icon = (BubbleTextView) holder.itemView;
                 icon.reset();
                 icon.applyFromApplicationInfo(adapterItem.itemInfo);
+                icon.setOnFocusChangeListener(mIconFocusListener);
                 break;
             }
             case VIEW_TYPE_EMPTY_SEARCH: {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index c783ee1..73861c1 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -119,6 +119,10 @@
             getReleaseFlag(301680992, "CUSTOM_LPNH_THRESHOLDS", DISABLED,
                     "Add dev options to customize the LPNH trigger slop and milliseconds");
 
+    public static final BooleanFlag ANIMATE_LPNH =
+            getReleaseFlag(308693847, "ANIMATE_LPNH", TEAMFOOD,
+                    "Animates navbar when long pressing");
+
     public static final IntFlag LPNH_SLOP_PERCENTAGE =
             getIntFlag(301680992, "LPNH_SLOP_PERCENTAGE", 100,
                     "Controls touch slop percentage for lpnh");
@@ -271,7 +275,7 @@
                     "Enables long pressing on the bottom bar nav handle to trigger events.");
 
     public static final BooleanFlag ENABLE_SEARCH_HAPTIC_HINT =
-            getReleaseFlag(303023676, "ENABLE_SEARCH_HAPTIC_HINT", TEAMFOOD,
+            getReleaseFlag(303023676, "ENABLE_SEARCH_HAPTIC_HINT", ENABLED,
                     "Enables haptic hint when long pressing on the bottom bar nav handle.");
 
     // TODO(Block 17): Clean up flags
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 18200f6..69fa673 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -169,6 +169,9 @@
                 LauncherPrefs.get(getContext())
                         .put(THEMED_ICONS, values.getAsBoolean(BOOLEAN_VALUE));
                 getContext().getContentResolver().notifyChange(uri, null);
+                mActivePreviews.values().forEach(observer ->
+                        observer.renderer.refreshIcons()
+                );
                 return 1;
             }
             default:
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 3330448..346f644 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -35,9 +35,12 @@
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
 import android.content.res.TypedArray;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
@@ -76,6 +79,7 @@
 import com.android.launcher3.celllayout.CellPosMapper;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.icons.IconProvider;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
@@ -83,6 +87,7 @@
 import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.InstallSessionHelper;
@@ -188,6 +193,8 @@
     private final SparseIntArray mWallpaperColorResources;
     private final SparseArray<Size> mLauncherWidgetSpanInfo;
 
+    private final Map<BubbleTextView, WorkspaceItemInfo> mIcons = new HashMap<>();
+
     public LauncherPreviewRenderer(Context context,
             InvariantDeviceProfile idp,
             WallpaperColors wallpaperColorsOverride,
@@ -366,11 +373,43 @@
         return CellPosMapper.DEFAULT;
     }
 
+    /**
+     * Refreshes icon to update based on resource changes.
+     */
+    public void refreshIcons() {
+        mUiHandler.post(() -> {
+                    IconProvider iconProvider = null;
+                    int iconDpi = -1;
+                    for (Map.Entry<BubbleTextView, WorkspaceItemInfo> entry : mIcons.entrySet()) {
+                        BubbleTextView icon = entry.getKey();
+                        ItemInfoWithIcon info = entry.getValue();
+                        // get monochrome themed icon if it was not initially cached
+                        if (info.bitmap.getMono() == null) {
+                            if (iconProvider == null || iconDpi == -1) {
+                                LauncherAppState appState = LauncherAppState.getInstance(mContext);
+                                iconProvider = appState.getIconProvider();
+                                iconDpi = appState.getInvariantDeviceProfile().fillResIconDpi;
+                            }
+                            LauncherActivityInfo activityInfo = mContext.getSystemService(
+                                            LauncherApps.class)
+                                    .resolveActivity(info.getIntent(), info.user);
+                            Drawable iconDrawable = iconProvider.getIcon(activityInfo,  iconDpi);
+                            LauncherIcons iconFactory = LauncherIcons.obtain(mContext);
+                            info.bitmap = iconFactory.createBadgedIconBitmap(iconDrawable);
+                        }
+                        // update icon based on whether themed icon is enabled
+                        icon.reapplyItemInfo(info);
+                    }
+                }
+        );
+    }
+
     private void inflateAndAddIcon(WorkspaceItemInfo info) {
         CellLayout screen = mWorkspaceScreens.get(info.screenId);
         BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
                 R.layout.app_icon, screen, false);
         icon.applyFromWorkspaceItem(info);
+        mIcons.put(icon, info);
         addInScreenFromBind(icon, info);
     }
 
@@ -477,6 +516,8 @@
                 currentWorkspaceItems, otherWorkspaceItems);
         filterCurrentWorkspaceItems(currentScreenIds, dataModel.appWidgets, currentAppWidgets,
                 otherAppWidgets);
+
+        mIcons.clear();
         for (ItemInfo itemInfo : currentWorkspaceItems) {
             switch (itemInfo.itemType) {
                 case Favorites.ITEM_TYPE_APPLICATION:
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 683354b..1bac765 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -201,6 +201,13 @@
         }
     }
 
+    /**
+     * Refreshes icon to update based on resource changes.
+     */
+    public void refreshIcons() {
+        mRenderer.refreshIcons();
+    }
+
     /***
      * Generates a new context overriding the theme color and the display size without affecting the
      * main application context
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 6b08153..685e4f1 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -415,8 +415,7 @@
     private void orientAboutObject(boolean allowAlignLeft, boolean allowAlignRight) {
         measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
 
-        int extraVerticalSpace = mArrowHeight + mArrowOffsetVertical
-                + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
+        int extraVerticalSpace = mArrowHeight + mArrowOffsetVertical + getExtraVerticalOffset();
         // The margins are added after we call this method, so we need to account for them here.
         int numVisibleChildren = 0;
         for (int i = getChildCount() - 1; i >= 0; --i) {
@@ -632,6 +631,10 @@
         mOpenCloseAnimator.start();
     }
 
+    public int getExtraVerticalOffset() {
+        return getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
+    }
+
     protected AnimatorSet getOpenCloseAnimator(boolean isOpening, int scaleDuration,
             int fadeStartDelay, int fadeDuration, int childFadeStartDelay, int childFadeDuration,
             Interpolator interpolator) {
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 228af4c..650fbcc 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -18,7 +18,6 @@
 
 import static android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED;
 
-import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
 import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT;
 
 import static com.android.launcher3.BuildConfig.IS_DEBUG_DEVICE;
@@ -34,7 +33,6 @@
 import android.view.MenuItem;
 import android.view.View;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.view.WindowCompat;
@@ -290,8 +288,6 @@
                 if (highlighter != null) {
                     getView().postDelayed(highlighter, DELAY_HIGHLIGHT_DURATION_MILLIS);
                     mPreferenceHighlighted = true;
-                } else {
-                    requestAccessibilityFocus(getListView());
                 }
             }
 
@@ -350,14 +346,5 @@
                     list, position, screen.findPreference(mHighLightKey))
                     : null;
         }
-
-        private void requestAccessibilityFocus(@NonNull final RecyclerView rv) {
-            rv.post(() -> {
-                if (!rv.hasFocus() && rv.getChildCount() > 0) {
-                    rv.getChildAt(0)
-                            .performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null);
-                }
-            });
-        }
     }
 }
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index eb45ded..3e80e6b 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -158,7 +158,6 @@
     public static final String PERMANENT_DIAG_TAG = "TaplTarget";
     public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
     public static final String ICON_MISSING = "b/282963545";
-    public static final String SPLIT_LEAK = "b/302551868";
 
     public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
     public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
new file mode 100644
index 0000000..80f73cb
--- /dev/null
+++ b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import static com.android.launcher3.ui.TaplTestsLauncher3.initialize;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.view.KeyEvent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.tapl.HomeAllApps;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TaplKeyboardFocusTest extends AbstractLauncherUiTest {
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        initialize(this);
+    }
+
+    @Test
+    public void testAllAppsFocusApp() {
+        final HomeAllApps allApps = mLauncher.goHome().switchToAllApps();
+        assertTrue("Launcher internal state is not All Apps",
+                isInState(() -> LauncherState.ALL_APPS));
+        allApps.freeze();
+        try {
+            mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
+            executeOnLauncher(launcher -> assertNotNull("No focused child.",
+                    launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()));
+        } finally {
+            allApps.unfreeze();
+        }
+    }
+
+    @Test
+    public void testAllAppsExitSearchAndFocusApp() {
+        final HomeAllApps allApps = mLauncher.goHome().switchToAllApps();
+        assertTrue("Launcher internal state is not All Apps",
+                isInState(() -> LauncherState.ALL_APPS));
+        allApps.freeze();
+        try {
+            executeOnLauncher(launcher -> launcher.getAppsView().getSearchView().requestFocus());
+            waitForLauncherCondition("Search view does not have focus.",
+                    launcher -> launcher.getAppsView().getSearchView().hasFocus());
+
+            mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
+            executeOnLauncher(launcher -> assertNotNull("No focused child.",
+                    launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()));
+        } finally {
+            allApps.unfreeze();
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 4184868..9bfafcf 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -187,7 +187,7 @@
             Utilities.enableRunningInTestHarnessForTests();
             mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
                             TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString())
-                            .getString("result"));
+                    .getString("result"));
             mLauncher.setOnSettledStateAction(
                     containerType -> executeOnLauncher(
                             launcher ->
@@ -248,6 +248,7 @@
     public void setUp() throws Exception {
         mLauncher.onTestStart();
 
+        waitForSetupWizardDismissal();
         if (TestStabilityRule.isPresubmit()) {
             aggressivelyUnlockSysUi();
         } else {
@@ -308,6 +309,36 @@
         Log.d(TAG, "Keyguard is not visible");
     }
 
+    // b/309008042
+    private static boolean sFirstTimeWaitingForWizard = true;
+
+    // b/309008042
+    static {
+        waitForSetupWizardDismissal();
+    }
+
+    // b/309008042
+    // TODO(309471958) Productize killing/dismissal of setup wizard.
+    /** Waits for setup wizard to go away. */
+    public static void waitForSetupWizardDismissal() {
+        if (sFirstTimeWaitingForWizard && TestStabilityRule.isPresubmit()) {
+            try {
+                UiDevice.getInstance(getInstrumentation()).executeShellCommand(
+                        "am force-stop com.google.android.setupwizard");
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        final boolean wizardDismissed = TestHelpers.wait(
+                Until.gone(By.pkg("com.google.android.setupwizard").depth(0)),
+                sFirstTimeWaitingForWizard ? 120000 : 0);
+        sFirstTimeWaitingForWizard = false;
+        // b/309496273
+//        Assert.assertTrue("Setup wizard is still visible",
+//                wizardDismissed);
+    }
+
     public static void verifyKeyguardInvisible() {
         final boolean keyguardAlreadyVisible = sSeenKeyguard;
 
@@ -422,6 +453,7 @@
     // flakiness.
     protected void waitForLauncherCondition(
             String message, Function<Launcher, Boolean> condition, long timeout) {
+        waitForSetupWizardDismissal();
         verifyKeyguardInvisible();
         if (!TestHelpers.isInLauncherProcess()) return;
         Wait.atMost(message, () -> getFromLauncher(condition), timeout, mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index a85b6bd..770fe14 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -25,6 +25,7 @@
 import androidx.test.uiautomator.UiObject2;
 
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -201,7 +202,8 @@
             OverviewTask task = getCurrentTask();
             mLauncher.assertNotNull("current task is null", task);
             mLauncher.scrollLeftByDistance(verifyActiveContainer(),
-                    task.getVisibleWidth() + mLauncher.getOverviewPageSpacing());
+                    mLauncher.getRealDisplaySize().x - task.getUiObject().getVisibleBounds().left
+                            + mLauncher.getOverviewPageSpacing());
 
             try (LauncherInstrumentation.Closable c2 =
                          mLauncher.addContextLayer("scrolled task off screen")) {
@@ -231,14 +233,14 @@
         final List<UiObject2> taskViews = getTasks();
         mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
 
-        // taskViews contains up to 3 task views: the 'main' (having the widest visible part) one
-        // in the center, and parts of its right and left siblings. Find the main task view by
-        // its width.
-        final UiObject2 widestTask = Collections.max(taskViews,
-                (t1, t2) -> Integer.compare(mLauncher.getVisibleBounds(t1).width(),
-                        mLauncher.getVisibleBounds(t2).width()));
-
-        return new OverviewTask(mLauncher, widestTask, this);
+        final List<OverviewTask> overviewTasks = taskViews.stream().map(
+                task -> new OverviewTask(mLauncher, task, this)).toList();
+        // The widest, and most top-right task should be the current task
+        return Collections.max(overviewTasks,
+                Comparator.comparingInt(OverviewTask::getVisibleWidth)
+                        .thenComparingInt(OverviewTask::getTaskCenterX)
+                        .thenComparing(
+                                Comparator.comparing(OverviewTask::getTaskCenterY).reversed()));
     }
 
     /** Returns an overview task matching TestActivity {@param activityNumber}. */
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 307f192..17169b3 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1608,8 +1608,11 @@
         scroll(
                 container,
                 Direction.LEFT,
-                new Rect(leftGestureMargin, 0,
-                        containerRect.width() - distance - rightGestureMarginInContainer, 0),
+                new Rect(leftGestureMargin,
+                        0,
+                        Math.max(containerRect.width() - distance - leftGestureMargin,
+                                rightGestureMarginInContainer),
+                        0),
                 10,
                 true);
     }
@@ -1782,7 +1785,7 @@
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
-    boolean isGridOnlyOverviewEnabled() {
+    public boolean isGridOnlyOverviewEnabled() {
         return getTestInfo(TestProtocol.REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW).getBoolean(
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
@@ -2225,7 +2228,7 @@
             int bottomBound = Math.min(
                     containerBounds.bottom,
                     getRealDisplaySize().y - getImeInsets().bottom);
-            int y = (bottomBound - containerBounds.top) / 2;
+            int y = (bottomBound + containerBounds.top) / 2;
             // Do not tap in the status bar.
             y = Math.max(y, getWindowInsets().top);
 
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 06fac48..8a34f0d 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -73,10 +73,13 @@
      * Calculates the visible height for split tasks, containing 2 snapshot tiles and a divider.
      */
     private int getCombinedSplitTaskHeight() {
-        UiObject2 taskSnapshot1 =
-                mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_1);
-        UiObject2 taskSnapshot2 =
-                mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_2);
+        UiObject2 taskSnapshot1 = findObjectInTask(TASK_SNAPSHOT_1);
+        UiObject2 taskSnapshot2 = findObjectInTask(TASK_SNAPSHOT_2);
+
+        // If the split task is partly off screen, taskSnapshot1 can be invisible.
+        if (taskSnapshot1 == null) {
+            return taskSnapshot2.getVisibleBounds().height();
+        }
 
         int top = Math.min(
                 taskSnapshot1.getVisibleBounds().top, taskSnapshot2.getVisibleBounds().top);
@@ -102,10 +105,8 @@
      * Calculates the visible width for split tasks, containing 2 snapshot tiles and a divider.
      */
     private int getCombinedSplitTaskWidth() {
-        UiObject2 taskSnapshot1 =
-                mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_1);
-        UiObject2 taskSnapshot2 =
-                mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_2);
+        UiObject2 taskSnapshot1 = findObjectInTask(TASK_SNAPSHOT_1);
+        UiObject2 taskSnapshot2 = findObjectInTask(TASK_SNAPSHOT_2);
 
         int left = Math.min(
                 taskSnapshot1.getVisibleBounds().left, taskSnapshot2.getVisibleBounds().left);
@@ -116,11 +117,15 @@
     }
 
     int getTaskCenterX() {
-        return mTask.getVisibleCenter().x;
+        return mTask.getParent().getVisibleCenter().x;
+    }
+
+    int getTaskCenterY() {
+        return mTask.getParent().getVisibleCenter().y;
     }
 
     float getExactCenterX() {
-        return mTask.getVisibleBounds().exactCenterX();
+        return mTask.getParent().getVisibleBounds().exactCenterX();
     }
 
     UiObject2 getUiObject() {
@@ -144,7 +149,8 @@
 
             boolean taskWasFocused = mLauncher.isTablet() && getVisibleHeight() == mLauncher
                     .getFocusedTaskHeightForTablet();
-            List<Integer> originalTasksCenterX = getCurrentTasksCenterXList();
+            List<Integer> originalTasksCenterX =
+                    getCurrentTasksCenterXList().stream().sorted().toList();
             boolean isClearAllVisibleBeforeDismiss = mOverview.isClearAllVisible();
 
             dismissBySwipingUp();
@@ -155,7 +161,8 @@
                             mOverview.getFocusedTaskForTablet());
                 }
                 if (!isClearAllVisibleBeforeDismiss) {
-                    List<Integer> currentTasksCenterX = getCurrentTasksCenterXList();
+                    List<Integer> currentTasksCenterX =
+                            getCurrentTasksCenterXList().stream().sorted().toList();
                     if (originalTasksCenterX.size() == currentTasksCenterX.size()) {
                         // Check for the same number of visible tasks before and after to
                         // avoid asserting on cases of shifting all tasks to close the distance
@@ -173,7 +180,7 @@
         // Dismiss the task via flinging it up.
         final Rect taskBounds = mLauncher.getVisibleBounds(mTask);
         final int centerX = taskBounds.centerX();
-        final int centerY = taskBounds.centerY();
+        final int centerY = taskBounds.bottom - 1;
         mLauncher.executeAndWaitForLauncherEvent(
                 () -> mLauncher.linearGesture(centerX, centerY, centerX, 0, 10, false,
                         LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER),
@@ -253,6 +260,10 @@
     }
 
     boolean isTaskSplit() {
-        return mLauncher.findObjectInContainer(mTask.getParent(), "bottomright_snapshot") != null;
+        return findObjectInTask(TASK_SNAPSHOT_2) != null;
+    }
+
+    private UiObject2 findObjectInTask(String resName) {
+        return mTask.getParent().findObject(mLauncher.getOverviewObjectSelector(resName));
     }
 }