Merge "Ignore all launcher3 flaky test so that they come back online" into tm-qpr-dev
diff --git a/quickstep/res/layout/taskbar_edu.xml b/quickstep/res/layout/taskbar_edu.xml
index 10444f1..d7daea3 100644
--- a/quickstep/res/layout/taskbar_edu.xml
+++ b/quickstep/res/layout/taskbar_edu.xml
@@ -46,7 +46,7 @@
             android:id="@+id/edu_start_button"
             android:layout_width="wrap_content"
             android:layout_height="36dp"
-            android:layout_marginBottom="92dp"
+            android:layout_marginBottom="18dp"
             android:layout_marginTop="32dp"
             app:layout_constraintTop_toBottomOf="@id/content"
             app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 311f37d..1eff992 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -78,10 +78,8 @@
     <string name="allset_title" msgid="5021126669778966707">"എല്ലാം സജ്ജീകരിച്ചു!"</string>
     <string name="allset_hint" msgid="2384632994739392447">"ഹോമിലേക്ക് പോകാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"നിങ്ങളുടെ ഹോം സ്ക്രീനിലേക്ക് പോകാൻ ഹോം ബട്ടൺ ടാപ്പ് ചെയ്യുക"</string>
-    <!-- no translation found for allset_description_generic (5385500062202019855) -->
-    <skip />
-    <!-- no translation found for default_device_name (6660656727127422487) -->
-    <skip />
+    <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>
     <string name="action_share" msgid="2648470652637092375">"പങ്കിടുക"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"സ്ക്രീൻഷോട്ട്"</string>
@@ -94,8 +92,7 @@
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"റദ്ദാക്കുക"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ഒഴിവാക്കുക"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"സ്‌ക്രീൻ റൊട്ടേറ്റ് ചെയ്യുക"</string>
-    <!-- no translation found for taskbar_edu_a11y_title (5417986057866415355) -->
-    <skip />
+    <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ടാസ്‌ക്ബാർ മാർഗ്ഗനിർദ്ദേശ വിൻഡോ"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"ടാസ്ക്ക്ബാർ വിവര പാനൽ ദൃശ്യമായി"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"ടാസ്ക്ക്ബാർ വിവര പാനൽ അടച്ചു"</string>
     <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ആപ്പുകൾ മാറാൻ ടാസ്ക്ക്ബാർ ഉപയോഗിക്കുക"</string>
@@ -112,10 +109,8 @@
     <string name="taskbar_button_recents" msgid="7273376136216613134">"അടുത്തിടെയുള്ളവ"</string>
     <string name="taskbar_button_notifications" msgid="7471740351507357318">"അറിയിപ്പുകൾ"</string>
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ദ്രുത ക്രമീകരണം"</string>
-    <!-- no translation found for taskbar_a11y_title (6432169809852243110) -->
-    <skip />
-    <!-- no translation found for taskbar_phone_a11y_title (4933360237131229395) -->
-    <skip />
+    <string name="taskbar_a11y_title" msgid="6432169809852243110">"ടാസ്‌ക്ബാർ"</string>
+    <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"നാവിഗേഷൻ ബാർ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"മുകളിലേക്കോ ഇടത്തേക്കോ നീക്കുക"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"താഴേക്കോ വലത്തേക്കോ നീക്കുക"</string>
 </resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index cb3f69a..b17d415 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -78,10 +78,8 @@
     <string name="allset_title" msgid="5021126669778966707">"அனைத்தையும் அமைத்துவிட்டீர்கள்!"</string>
     <string name="allset_hint" msgid="2384632994739392447">"முகப்புத் திரைக்குச் செல்ல மேல்நோக்கி ஸ்வைப் செய்யுங்கள்"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"முகப்புத் திரைக்குச் செல்வதற்கு முகப்பு பட்டனைத் தட்டவும்"</string>
-    <!-- no translation found for allset_description_generic (5385500062202019855) -->
-    <skip />
-    <!-- no translation found for default_device_name (6660656727127422487) -->
-    <skip />
+    <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>
     <string name="action_share" msgid="2648470652637092375">"பகிர்"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ஸ்கிரீன்ஷாட்"</string>
@@ -94,8 +92,7 @@
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ரத்துசெய்"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"தவிர்"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"திரையைச் சுழற்றும்"</string>
-    <!-- no translation found for taskbar_edu_a11y_title (5417986057866415355) -->
-    <skip />
+    <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"செயல் பட்டியைப் பயன்படுத்தும் விதம்"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் காட்டப்படுகிறது"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் மூடப்பட்டது"</string>
     <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ஆப்ஸிற்கு இடையே மாற பணிப்பட்டியைப் பயன்படுத்தவும்"</string>
@@ -112,10 +109,8 @@
     <string name="taskbar_button_recents" msgid="7273376136216613134">"சமீபத்தியவை"</string>
     <string name="taskbar_button_notifications" msgid="7471740351507357318">"அறிவிப்புகள்"</string>
     <string name="taskbar_button_quick_settings" msgid="227662894293189391">"விரைவு அமைப்புகள்"</string>
-    <!-- no translation found for taskbar_a11y_title (6432169809852243110) -->
-    <skip />
-    <!-- no translation found for taskbar_phone_a11y_title (4933360237131229395) -->
-    <skip />
+    <string name="taskbar_a11y_title" msgid="6432169809852243110">"செயல் பட்டி"</string>
+    <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"வழிசெலுத்தல் பட்டி"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"மேலே/இடதுபுறம் நகர்த்தும்"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"கீழே/வலதுபுறம் நகர்த்தும்"</string>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index c54d119..4fbe8cf 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -30,7 +30,6 @@
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -51,7 +50,7 @@
 import java.util.stream.Collectors;
 
 @TargetApi(Build.VERSION_CODES.P)
-public class PredictionRowView<T extends Context & ActivityContext & DeviceProfileListenable>
+public class PredictionRowView<T extends Context & ActivityContext>
         extends LinearLayout implements OnDeviceProfileChangeListener, FloatingHeaderRow {
 
     private final T mActivityContext;
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 0c8952d..a205d19 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -42,7 +42,8 @@
      * Whether desktop mode is supported.
      */
     private boolean isDesktopModeSupported() {
-        return SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false);
+        return SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false)
+            || SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
index b4052e3..82d1830 100644
--- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
@@ -19,18 +19,16 @@
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.util.Themes;
-import com.android.launcher3.views.AppLauncher;
+import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
 import java.util.List;
 
 // TODO(b/218912746): Share more behavior to avoid all apps context depending directly on taskbar.
 /** Base for common behavior between taskbar window contexts. */
-public abstract class BaseTaskbarContext extends ContextThemeWrapper implements AppLauncher,
-        DeviceProfileListenable {
+public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext {
 
     protected final LayoutInflater mLayoutInflater;
     private final List<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 02206ce..22f7f13 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -38,6 +38,7 @@
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.InstanceIdSequence;
@@ -45,7 +46,6 @@
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.OnboardingPrefs;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.RecentsAnimationCallbacks;
 import com.android.quickstep.views.RecentsView;
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 2435236..cbee58b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -81,6 +81,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AlphaUpdateListener;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory;
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter;
@@ -89,7 +90,6 @@
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.AnimatedFloat;
 import com.android.systemui.shared.rotation.FloatingRotationButton;
 import com.android.systemui.shared.rotation.RotationButton;
 import com.android.systemui.shared.rotation.RotationButtonController;
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index af46df4..74e7375 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -28,13 +28,13 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
-import com.android.quickstep.AnimatedFloat;
 import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
 
 import java.io.PrintWriter;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 01ec5f3..83b8d83 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -877,6 +877,16 @@
         mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
     }
 
+    /** Called when we want to hide the overlay window when user performs swipe up gesture. */
+    public void onSwipeToHideOverlay() {
+        mControllers.taskbarOverlayController.hideWindow();
+    }
+
+    /** Returns {@code true} if taskbar is stashed. */
+    public boolean isTaskbarStashed() {
+        return mControllers.taskbarStashController.isStashed();
+    }
+
     /**
      * Called to start the taskbar translation spring to its settled translation (0).
      */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 0328df9..bc41c2b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -21,9 +21,9 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
-import com.android.quickstep.AnimatedFloat;
 import com.android.systemui.shared.rotation.RotationButtonController;
 
 import java.io.PrintWriter;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index e54fc00..cd27a46 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -23,11 +23,11 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.util.DimensionUtils;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.TouchController;
-import com.android.quickstep.AnimatedFloat;
 
 import java.io.PrintWriter;
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
index 2cb05ff..d3f1b2f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
@@ -15,11 +15,11 @@
  */
 package com.android.launcher3.taskbar;
 
-import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_EDU;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-
 import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
@@ -62,20 +62,21 @@
                         : R.layout.taskbar_edu_pages_persistent,
                 mPagedView,
                 true);
+
+        // Provide enough room for taskbar.
+        View startButton = mTaskbarEduView.findViewById(R.id.edu_start_button);
+        ViewGroup.MarginLayoutParams layoutParams =
+                (ViewGroup.MarginLayoutParams) startButton.getLayoutParams();
+        DeviceProfile dp = overlayContext.getDeviceProfile();
+        layoutParams.bottomMargin += DisplayController.isTransientTaskbar(overlayContext)
+                ? dp.taskbarSize + dp.transientTaskbarMargin
+                : dp.taskbarSize;
+
         mTaskbarEduView.init(new TaskbarEduCallbacks());
 
         mControllers.navbarButtonsViewController.setSlideInViewVisible(true);
-        TaskbarStashController stashController = mControllers.taskbarStashController;
-        stashController.updateStateForFlag(FLAG_STASHED_IN_APP_EDU, true);
-        stashController.applyState(overlayController.getOpenDuration());
-
-        mTaskbarEduView.setOnCloseBeginListener(() -> {
-            mControllers.navbarButtonsViewController.setSlideInViewVisible(false);
-            // Post in case view is closing due to gesture navigation. If a gesture is in progress,
-            // wait to unstash until after the gesture is finished.
-            MAIN_EXECUTOR.post(() -> stashController.resetFlagIfNoGestureInProgress(
-                    FLAG_STASHED_IN_APP_EDU));
-        });
+        mTaskbarEduView.setOnCloseBeginListener(
+                () -> mControllers.navbarButtonsViewController.setSlideInViewVisible(false));
         mTaskbarEduView.addOnCloseListener(() -> mTaskbarEduView = null);
         mTaskbarEduView.show();
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
index f7aafe0..ffaee45 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
@@ -30,10 +30,10 @@
 import android.view.MotionEvent;
 import android.view.View;
 
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.TouchController;
-import com.android.quickstep.AnimatedFloat;
 
 /**
  * Controller for taskbar when force visible in immersive mode is set.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index b74dd21..4ad3858 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -35,12 +35,12 @@
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.uioverrides.states.OverviewState;
 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.RecentsAnimationCallbacks;
 import com.android.quickstep.RecentsAnimationController;
 import com.android.quickstep.views.RecentsView;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index ce191b7..88767dd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -22,7 +22,7 @@
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
-import com.android.quickstep.AnimatedFloat;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.quickstep.SystemUiProxy;
 
 import java.io.PrintWriter;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 3d98f6e..95337ce 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -52,11 +52,11 @@
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.SystemUiProxy;
 
 import java.io.PrintWriter;
@@ -82,7 +82,6 @@
     public static final int FLAG_IN_SETUP = 1 << 8; // In the Setup Wizard
     public static final int FLAG_STASHED_SMALL_SCREEN = 1 << 9; // phone screen gesture nav, stashed
     public static final int FLAG_STASHED_IN_APP_AUTO = 1 << 10; // Autohide (transient taskbar).
-    public static final int FLAG_STASHED_IN_APP_EDU = 1 << 11; // EDU is visible.
 
     // If any of these flags are enabled, isInApp should return true.
     private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
@@ -91,7 +90,7 @@
     private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
             | FLAG_STASHED_IN_SYSUI_STATE | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP
             | FLAG_STASHED_IN_APP_IME | FLAG_STASHED_IN_TASKBAR_ALL_APPS
-            | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO | FLAG_STASHED_IN_APP_EDU;
+            | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO;
 
     private static final int FLAGS_STASHED_IN_APP_IGNORING_IME =
             FLAGS_STASHED_IN_APP & ~FLAG_STASHED_IN_APP_IME;
@@ -101,8 +100,7 @@
     // Currently any flag that causes us to stash in an app is included, except for IME or All Apps
     // since those cover the underlying app anyway and thus the app shouldn't change insets.
     private static final int FLAGS_REPORT_STASHED_INSETS_TO_APP = FLAGS_STASHED_IN_APP
-            & ~FLAG_STASHED_IN_APP_IME & ~FLAG_STASHED_IN_TASKBAR_ALL_APPS
-            & ~FLAG_STASHED_IN_APP_EDU;
+            & ~FLAG_STASHED_IN_APP_IME & ~FLAG_STASHED_IN_TASKBAR_ALL_APPS;
 
     /**
      * How long to stash/unstash when manually invoked via long press.
@@ -728,7 +726,6 @@
         // Only update the following flags when system gesture is not in progress.
         boolean shouldStashForIme = shouldStashForIme();
         updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false);
-        updateStateForFlag(FLAG_STASHED_IN_APP_EDU, false);
         if (hasAnyFlag(FLAG_STASHED_IN_APP_IME) != shouldStashForIme) {
             updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme);
             applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 1a7ec13..5dba444 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -15,8 +15,8 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.launcher3.anim.AnimatedFloat.VALUE;
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
-import static com.android.quickstep.AnimatedFloat.VALUE;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -26,10 +26,10 @@
 import androidx.annotation.Nullable;
 import androidx.dynamicanimation.animation.SpringForce;
 
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.anim.SpringAnimationBuilder;
 import com.android.launcher3.util.DisplayController;
-import com.android.quickstep.AnimatedFloat;
 
 import java.io.PrintWriter;
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index a059295..b3b53c2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -25,6 +25,7 @@
 
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 
@@ -84,7 +85,9 @@
      * Manually closes the overlay window.
      */
     public void hideOverlayWindow() {
-        mControllers.taskbarOverlayController.hideWindow();
+        if (!DisplayController.isTransientTaskbar(mControllers.taskbarActivityContext)) {
+            mControllers.taskbarOverlayController.hideWindow();
+        }
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index d14eeab..5c9b51a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -19,13 +19,13 @@
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.launcher3.anim.AnimatedFloat.VALUE;
 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
 import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
 import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE;
 import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
-import static com.android.quickstep.AnimatedFloat.VALUE;
 
 import android.annotation.NonNull;
 import android.graphics.Rect;
@@ -45,6 +45,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AlphaUpdateListener;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.anim.PendingAnimation;
@@ -59,7 +60,6 @@
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
-import com.android.quickstep.AnimatedFloat;
 
 import java.io.PrintWriter;
 import java.util.function.Predicate;
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index 4165486..721f816 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar.allapps;
 
 import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_AUTO;
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_TASKBAR_ALL_APPS;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
@@ -28,6 +29,7 @@
 import com.android.launcher3.taskbar.TaskbarStashController;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
+import com.android.launcher3.util.DisplayController;
 
 /**
  * Handles the {@link TaskbarAllAppsContainerView} behavior and synchronizes its transitions with
@@ -88,18 +90,25 @@
     }
 
     private void setUpTaskbarStashing() {
-        mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, true);
+        mTaskbarStashController.updateStateForFlag(
+                DisplayController.isTransientTaskbar(mContext)
+                        ? FLAG_STASHED_IN_APP_AUTO
+                        : FLAG_STASHED_IN_TASKBAR_ALL_APPS,
+                true);
         mTaskbarStashController.applyState(
                 ALL_APPS.getTransitionDuration(mContext, true /* isToState */));
+
         mNavbarButtonsViewController.setSlideInViewVisible(true);
         mSlideInView.setOnCloseBeginListener(() -> {
             mNavbarButtonsViewController.setSlideInViewVisible(false);
             AbstractFloatingView.closeOpenContainer(
                     mContext, AbstractFloatingView.TYPE_ACTION_POPUP);
-            // Post in case view is closing due to gesture navigation. If a gesture is in progress,
-            // wait to unstash until after the gesture is finished.
-            MAIN_EXECUTOR.post(() -> mTaskbarStashController.resetFlagIfNoGestureInProgress(
-                    FLAG_STASHED_IN_TASKBAR_ALL_APPS));
+            if (!DisplayController.isTransientTaskbar(mContext)) {
+                // Post in case view is closing due to gesture navigation. If a gesture is in
+                // progress, wait to unstash until after the gesture is finished.
+                MAIN_EXECUTOR.post(() -> mTaskbarStashController.resetFlagIfNoGestureInProgress(
+                        FLAG_STASHED_IN_TASKBAR_ALL_APPS));
+            }
         });
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index fd184c6..2a42175 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -20,12 +20,11 @@
 
 import android.content.Context;
 
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.ActivityContext;
 
 /**
  * Definition for AllApps state
@@ -40,7 +39,7 @@
     }
 
     @Override
-    public <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable>
+    public <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
     int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState) {
         return isToState
                 ? context.getDeviceProfile().allAppsOpenDuration
@@ -78,7 +77,7 @@
     }
 
     @Override
-    protected <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+    protected <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
             float getDepthUnchecked(DEVICE_PROFILE_CONTEXT context) {
         if (context.getDeviceProfile().isTablet) {
             return context.getDeviceProfile().bottomSheetDepth;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 922679b..2c7e46c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -62,6 +62,7 @@
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.states.StateAnimationConfig;
@@ -69,7 +70,6 @@
 import com.android.launcher3.touch.BothAxesSwipeDetector;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.TouchController;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.LayoutUtils;
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 374b839..d4bebea 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -58,6 +58,7 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.anim.SpringAnimationBuilder;
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 8e07376..83f2a0a 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -34,6 +34,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
+import android.util.Log;
 import android.util.SparseIntArray;
 
 import androidx.annotation.NonNull;
@@ -54,6 +55,8 @@
  * and provide callers the relevant classes.
  */
 public final class OverviewComponentObserver {
+    private static final String TAG = "OverviewComponentObserver";
+
     private final BroadcastReceiver mUserPreferenceChangeReceiver =
             new SimpleBroadcastReceiver(this::updateOverviewTargets);
     private final BroadcastReceiver mOtherHomeAppUpdateReceiver =
@@ -146,7 +149,12 @@
             }
         }
 
-        if (!mDeviceState.isHomeDisabled() && (defaultHome == null || mIsDefaultHome)) {
+        // TODO(b/258022658): Remove temporary logging.
+        Log.i(TAG, "updateOverviewTargets: mIsHomeDisabled=" + mIsHomeDisabled
+                + ", isDefaultHomeNull=" + (defaultHome == null)
+                + ", mIsDefaultHome=" + mIsDefaultHome);
+
+        if (!mIsHomeDisabled && (defaultHome == null || mIsDefaultHome)) {
             // User default home is same as out home app. Use Overview integrated in Launcher.
             mActivityInterface = LauncherActivityInterface.INSTANCE;
             mIsHomeAndOverviewSame = true;
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index fdde45a..291f835 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -31,6 +31,7 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index eae79df..663525d 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -303,7 +303,8 @@
 
         private boolean isAvailable(BaseDraggingActivity activity, int displayId) {
             return ActivityManagerWrapper.getInstance().supportsFreeformMultiWindow(activity)
-                    && !SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false);
+                    && !SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false)
+                    && !SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
         }
     };
 
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index e8722e2..b7252bc 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -60,6 +60,7 @@
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index af6a45a..2565697 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -73,6 +73,7 @@
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.provider.RestoreDbTask;
 import com.android.launcher3.statehandlers.DesktopVisibilityController;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index db7e087..5374ff0 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -41,11 +41,11 @@
 import android.view.VelocityTracker;
 
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.DisplayController;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.MultiStateCallback;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
index 2462394..45ffa1c 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -28,12 +28,12 @@
 import android.graphics.Point;
 import android.view.MotionEvent;
 
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.util.DisplayController;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.MultiStateCallback;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
index 3a09490..c8326c4 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
@@ -53,8 +53,11 @@
     private final float mUnstashArea;
     private final float mScreenWidth;
 
-    private final int mTaskbarThresholdY;
-    private boolean mHasPassedTaskbarThreshold;
+    private final int mTaskbarNavThresholdY;
+    private final int mTaskbarAppWindowThresholdY;
+    private final boolean mTaskbarAlreadyOpen;
+    private boolean mHasPassedTaskbarNavThreshold;
+    private boolean mHasPassedTaskbarAppWindowThreshold;
 
     private final PointF mDownPos = new PointF();
     private final PointF mLastPos = new PointF();
@@ -73,11 +76,18 @@
 
         Resources res = context.getResources();
         mUnstashArea = res.getDimensionPixelSize(R.dimen.taskbar_unstash_input_area);
-        int taskbarThreshold = res.getDimensionPixelSize(ENABLE_TASKBAR_REVISED_THRESHOLDS.get()
+        int taskbarNavThreshold = res.getDimensionPixelSize(ENABLE_TASKBAR_REVISED_THRESHOLDS.get()
                 ? R.dimen.taskbar_nav_threshold_v2
                 : R.dimen.taskbar_nav_threshold);
+        int taskbarAppWindowThreshold = res.getDimensionPixelSize(
+                ENABLE_TASKBAR_REVISED_THRESHOLDS.get()
+                        ? R.dimen.taskbar_app_window_threshold_v2
+                        : R.dimen.taskbar_app_window_threshold);
         int screenHeight = taskbarActivityContext.getDeviceProfile().heightPx;
-        mTaskbarThresholdY = screenHeight - taskbarThreshold;
+        mTaskbarNavThresholdY = screenHeight - taskbarNavThreshold;
+        mTaskbarAppWindowThresholdY = screenHeight - taskbarAppWindowThreshold;
+        mTaskbarAlreadyOpen = mTaskbarActivityContext != null
+                && !mTaskbarActivityContext.isTaskbarStashed();
 
         mIsTransientTaskbar = DisplayController.isTransientTaskbar(context);
 
@@ -113,7 +123,8 @@
                         mDownPos.set(ev.getX(), ev.getY());
                         mLastPos.set(mDownPos);
 
-                        mHasPassedTaskbarThreshold = false;
+                        mHasPassedTaskbarNavThreshold = false;
+                        mHasPassedTaskbarAppWindowThreshold = false;
                         mTaskbarActivityContext.setAutohideSuspendFlag(
                                 FLAG_AUTOHIDE_SUSPEND_TOUCHING, true);
                         if (isInArea(x)) {
@@ -156,18 +167,23 @@
 
                         if (mIsTransientTaskbar) {
                             float dY = mLastPos.y - mDownPos.y;
-                            boolean passedTaskbarThreshold = dY < 0
-                                    && mLastPos.y < mTaskbarThresholdY;
+                            boolean passedTaskbarNavThreshold = dY < 0
+                                    && mLastPos.y < mTaskbarNavThresholdY;
+                            boolean passedTaskbarAppWindowThreshold = dY < 0
+                                    && mLastPos.y < mTaskbarAppWindowThresholdY;
 
-                            if (!mHasPassedTaskbarThreshold
-                                    && passedTaskbarThreshold) {
-                                mHasPassedTaskbarThreshold = true;
-
+                            if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) {
+                                mHasPassedTaskbarNavThreshold = true;
                                 mTaskbarActivityContext.onSwipeToUnstashTaskbar();
                             }
+                            if (mTaskbarAlreadyOpen || (!mHasPassedTaskbarAppWindowThreshold
+                                    && passedTaskbarAppWindowThreshold)) {
+                                mHasPassedTaskbarAppWindowThreshold = true;
+                                mTaskbarActivityContext.onSwipeToHideOverlay();
+                            }
 
                             if (dY < 0) {
-                                dY = -OverScroll.dampedScroll(-dY, mTaskbarThresholdY);
+                                dY = -OverScroll.dampedScroll(-dY, mTaskbarNavThresholdY);
                                 if (mTransitionCallback != null) {
                                     mTransitionCallback.onActionMove(dY);
                                 }
@@ -185,7 +201,8 @@
                         if (mTransitionCallback != null) {
                             mTransitionCallback.onActionEnd();
                         }
-                        mHasPassedTaskbarThreshold = false;
+                        mHasPassedTaskbarNavThreshold = false;
+                        mHasPassedTaskbarAppWindowThreshold = false;
                         break;
                 }
             }
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 036ddcc..e0262d0 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -58,9 +58,9 @@
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.util.Executors;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.TouchInteractionService.TISBinder;
 import com.android.quickstep.util.TISBindHelper;
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 6b016ce..05b246b 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -24,8 +24,8 @@
 import android.os.Build;
 
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.PendingAnimation;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.SwipeUpAnimationLogic;
 import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
 import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index d7ff0be..670ee9b 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -42,10 +42,10 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.OverviewComponentObserver;
 import com.android.quickstep.RecentsAnimationDeviceState;
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 1515c5b..44ad889 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -41,10 +41,10 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
 import com.android.launcher3.util.TraceHelper;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.BaseActivityInterface;
 import com.android.quickstep.TaskAnimationManager;
 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 8c43fd1..308249c 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -59,9 +59,10 @@
 // TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
 public class DesktopTaskView extends TaskView {
 
-    /** Flag to indicate whether desktop mode is available on the device */
-    public static final boolean DESKTOP_MODE_SUPPORTED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode", false);
+    /** Flags to indicate whether desktop mode is available on the device */
+    public static final boolean DESKTOP_MODE_SUPPORTED =
+            SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false)
+                    || SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
 
     private static final String TAG = DesktopTaskView.class.getSimpleName();
 
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 8b406ec..0e49769 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -135,6 +135,7 @@
 import com.android.launcher3.PagedView;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
@@ -159,7 +160,6 @@
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TranslateEdgeEffect;
 import com.android.launcher3.util.ViewPool;
-import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.BaseActivityInterface;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.RecentsAnimationController;
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 6b4d129..d79c022 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -40,8 +40,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"לוחצים לחיצה ארוכה על הווידג\'ט כדי להזיז אותו במסך הבית"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"הוספה למסך הבית"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"הווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g> נוסף למסך הבית"</string>
-    <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ווידג\'ט אחד}two{# ווידג\'טים}many{# ווידג\'טים}other{# ווידג\'טים}}"</string>
-    <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{קיצור דרך אחד}two{# קיצורי דרך}many{# קיצורי דרך}other{# קיצורי דרך}}"</string>
+    <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ווידג\'ט אחד}one{# ווידג\'טים}two{# ווידג\'טים}other{# ווידג\'טים}}"</string>
+    <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{קיצור דרך אחד}one{# קיצורי דרך}two{# קיצורי דרך}other{# קיצורי דרך}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"ווידג\'טים"</string>
     <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"חיפוש"</string>
@@ -89,7 +89,7 @@
     <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>
-    <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{לאפליקציה {app_name} יש התראה אחת}two{לאפליקציה {app_name} יש # התראות}many{לאפליקציה {app_name} יש # התראות}other{לאפליקציה {app_name} יש # התראות}}"</string>
+    <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{לאפליקציה {app_name} יש התראה אחת}one{לאפליקציה {app_name} יש # התראות}two{לאפליקציה {app_name} יש # התראות}other{לאפליקציה {app_name} יש # התראות}}"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"‏דף %1$d מתוך %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"‏מסך הבית %1$d מתוך %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"מסך הבית חדש"</string>
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 9bdc822..61707df 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -30,14 +30,13 @@
 
 import androidx.annotation.IntDef;
 
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.ViewCache;
-import com.android.launcher3.views.AppLauncher;
+import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.ScrimView;
 
 import java.io.PrintWriter;
@@ -48,8 +47,7 @@
 /**
  * Launcher BaseActivity
  */
-public abstract class BaseActivity extends Activity implements AppLauncher,
-        DeviceProfileListenable {
+public abstract class BaseActivity extends Activity implements ActivityContext {
 
     private static final String TAG = "BaseActivity";
 
diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java
index ec29b29..3e4e96b 100644
--- a/src/com/android/launcher3/CheckLongPressHelper.java
+++ b/src/com/android/launcher3/CheckLongPressHelper.java
@@ -17,11 +17,12 @@
 package com.android.launcher3;
 
 import android.os.Handler;
-import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 
+import com.android.launcher3.util.TouchUtil;
+
 /**
  * Utility class to handle tripper long press or right click on a view with custom timeout and
  * stylus event
@@ -64,7 +65,7 @@
                 cancelLongPress();
 
                 // Mouse right click should immediately trigger a long press
-                if (isMouseRightClickDownOrMove(ev)) {
+                if (TouchUtil.isMouseRightClickDownOrMove(ev)) {
                     mIsInMouseRightClick = true;
                     triggerLongPress();
                     final Handler handler = mView.getHandler();
@@ -176,14 +177,4 @@
         return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
                 && event.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
     }
-
-    /**
-     * Detect ACTION_DOWN or ACTION_MOVE from mouse right button. Note that we cannot detect
-     * ACTION_UP from mouse's right button because, in that case,
-     * {@link MotionEvent#getButtonState()} returns 0 for any mouse button (right, middle, right).
-     */
-    private static boolean isMouseRightClickDownOrMove(MotionEvent event) {
-        return event.isFromSource(InputDevice.SOURCE_MOUSE)
-                && ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0);
-    }
 }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 828066a..ce78fce 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -55,7 +55,6 @@
 import com.android.launcher3.util.WindowBounds;
 
 import java.io.PrintWriter;
-import java.util.List;
 import java.util.Locale;
 
 @SuppressLint("NewApi")
@@ -1631,35 +1630,6 @@
         void onDeviceProfileChanged(DeviceProfile dp);
     }
 
-    /** Allows registering listeners for {@link DeviceProfile} changes. */
-    public interface DeviceProfileListenable {
-
-        /** The current device profile. */
-        DeviceProfile getDeviceProfile();
-
-        /** Registered {@link OnDeviceProfileChangeListener} instances. */
-        List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners();
-
-        /** Notifies listeners of a {@link DeviceProfile} change. */
-        default void dispatchDeviceProfileChanged() {
-            DeviceProfile deviceProfile = getDeviceProfile();
-            List<OnDeviceProfileChangeListener> listeners = getOnDeviceProfileChangeListeners();
-            for (int i = listeners.size() - 1; i >= 0; i--) {
-                listeners.get(i).onDeviceProfileChanged(deviceProfile);
-            }
-        }
-
-        /** Register listener for {@link DeviceProfile} changes. */
-        default void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
-            getOnDeviceProfileChangeListeners().add(listener);
-        }
-
-        /** Unregister listener for {@link DeviceProfile} changes. */
-        default void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
-            getOnDeviceProfileChangeListeners().remove(listener);
-        }
-    }
-
     /**
      * Handler that deals with ItemInfo of the views for the DeviceProfile
      */
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1a6c68d..18ed0fc 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -43,7 +43,6 @@
 import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
 import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
-import static com.android.launcher3.config.FeatureFlags.SHOW_DELIGHTFUL_PAGINATION;
 import static com.android.launcher3.config.FeatureFlags.SHOW_DOT_PAGINATION;
 import static com.android.launcher3.logging.StatsLogManager.EventEnum;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -1280,8 +1279,7 @@
 
     @Override
     public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
-        if ((SHOW_DOT_PAGINATION.get() || SHOW_DELIGHTFUL_PAGINATION.get())
-                && WorkspacePageIndicator.class.getName().equals(name)) {
+        if ((SHOW_DOT_PAGINATION.get()) && WorkspacePageIndicator.class.getName().equals(name)) {
             return LayoutInflater.from(context).inflate(R.layout.page_indicator_dots,
                     (ViewGroup) parent, false);
         }
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 31a7d18..5dddc6f 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -41,6 +41,7 @@
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.uioverrides.states.AllAppsState;
 import com.android.launcher3.uioverrides.states.OverviewState;
+import com.android.launcher3.views.ActivityContext;
 
 import java.util.Arrays;
 
@@ -261,7 +262,7 @@
      *
      * 0 means completely zoomed in, without blurs. 1 is zoomed out, with blurs.
      */
-    public final  <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+    public final  <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
             float getDepth(DEVICE_PROFILE_CONTEXT context) {
         return getDepth(context,
                 BaseDraggingActivity.fromContext(context).getDeviceProfile().isMultiWindowMode);
@@ -272,7 +273,7 @@
      *
      * @see #getDepth(Context).
      */
-    public final <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+    public final <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
             float getDepth(DEVICE_PROFILE_CONTEXT context, boolean isMultiWindowMode) {
         if (isMultiWindowMode) {
             return 0;
@@ -280,7 +281,7 @@
         return getDepthUnchecked(context);
     }
 
-    protected <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+    protected <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
             float getDepthUnchecked(DEVICE_PROFILE_CONTEXT context) {
         return 0f;
     }
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 5c55b53..5296df1 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -27,13 +27,12 @@
 import androidx.core.graphics.ColorUtils;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.views.AppLauncher;
+import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
 
@@ -42,8 +41,8 @@
  *
  * @param <T> Type of context inflating all apps.
  */
-public class ActivityAllAppsContainerView<T extends Context & AppLauncher
-        & DeviceProfileListenable> extends BaseAllAppsContainerView<T> {
+public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
+        extends BaseAllAppsContainerView<T> {
 
     private static final long DEFAULT_SEARCH_TRANSITION_DURATION_MS = 300;
 
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index f308a25..65b4661 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -48,7 +48,6 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
@@ -81,8 +80,8 @@
  *
  * @param <T> Type of context inflating all apps.
  */
-public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext
-        & DeviceProfileListenable> extends SpringRelativeLayout implements DragSource, Insettable,
+public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext>
+        extends SpringRelativeLayout implements DragSource, Insettable,
         OnDeviceProfileChangeListener, OnActivePageChangedListener,
         ScrimView.ScrimDrawingController {
 
diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
index 4fb732d..20edf8a 100644
--- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
@@ -26,17 +26,17 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.allapps.AllAppsGridAdapter;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.views.AppLauncher;
+import com.android.launcher3.views.ActivityContext;
 
 /**
  * Provides views for local search results.
  */
-public class DefaultSearchAdapterProvider extends SearchAdapterProvider<AppLauncher> {
+public class DefaultSearchAdapterProvider extends SearchAdapterProvider<ActivityContext> {
 
     private final RecyclerView.ItemDecoration mDecoration;
     private View mHighlightedView;
 
-    public DefaultSearchAdapterProvider(AppLauncher launcher) {
+    public DefaultSearchAdapterProvider(ActivityContext launcher) {
         super(launcher);
         mDecoration = new RecyclerView.ItemDecoration() {
             @Override
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/src/com/android/launcher3/anim/AnimatedFloat.java
similarity index 95%
rename from quickstep/src/com/android/quickstep/AnimatedFloat.java
rename to src/com/android/launcher3/anim/AnimatedFloat.java
index 5ab3c58..b73621d 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/src/com/android/launcher3/anim/AnimatedFloat.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.quickstep;
+package com.android.launcher3.anim;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -98,12 +98,18 @@
         }
     }
 
+    /**
+     * Cancels the animation.
+     */
     public void cancelAnimation() {
         if (mValueAnimator != null) {
             mValueAnimator.cancel();
         }
     }
 
+    /**
+     * Ends the animation.
+     */
     public void finishAnimation() {
         if (mValueAnimator != null && mValueAnimator.isRunning()) {
             mValueAnimator.end();
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 5cab817..77c920c 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -307,10 +307,6 @@
             "SCROLL_TOP_TO_RESET", false, "Bring up IME and focus on "
             + "input when scroll to top if 'Always show keyboard' is enabled or in prefix state");
 
-    public static final BooleanFlag SHOW_DELIGHTFUL_PAGINATION = getDebugFlag(
-            "SHOW_DELIGHTFUL_PAGINATION", false,
-            "Enable showing the new 'delightful pagination' which is a brand"
-                    + " new animation for folder pagination and workspace pagination");
     public static final BooleanFlag POPUP_MATERIAL_U = new DeviceFlag(
             "POPUP_MATERIAL_U", false, "Switch popup UX to use material U");
 
@@ -335,7 +331,7 @@
                     + " nav mode and when transient taskbar is enabled.");
 
     public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(
-            "ENABLE_TRANSIENT_TASKBAR", false, "Enables transient taskbar.");
+            "ENABLE_TRANSIENT_TASKBAR", true, "Enables transient taskbar.");
 
     public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(
             "SECONDARY_DRAG_N_DROP_TO_PIN", false,
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 772913d..e7b0446 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -63,6 +63,7 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.InvariantDeviceProfile;
@@ -174,6 +175,7 @@
         }
     }
 
+    private final List<OnDeviceProfileChangeListener> mDpChangeListeners = new ArrayList<>();
     private final Handler mUiHandler;
     private final Context mContext;
     private final InvariantDeviceProfile mIdp;
@@ -331,6 +333,11 @@
     }
 
     @Override
+    public List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners() {
+        return mDpChangeListeners;
+    }
+
+    @Override
     public Hotseat getHotseat() {
         return mHotseat;
     }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index e9b6606..c324ce3 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.pageindicators;
 
-import static com.android.launcher3.config.FeatureFlags.SHOW_DELIGHTFUL_PAGINATION;
 import static com.android.launcher3.config.FeatureFlags.SHOW_DOT_PAGINATION;
 
 import android.animation.Animator;
@@ -32,7 +31,6 @@
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.AttributeSet;
@@ -48,7 +46,6 @@
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.util.Themes;
 
 /**
@@ -70,7 +67,6 @@
     private static final int PAGE_INDICATOR_ALPHA = 255;
     private static final int DOT_ALPHA = 128;
     private static final int DOT_GAP_FACTOR = 3;
-    private static final float DOT_GAP_FACTOR_FLOAT = 3.8f;
     private static final int VISIBLE_ALPHA = 1;
     private static final int INVISIBLE_ALPHA = 0;
     private Paint mPaginationPaint;
@@ -78,8 +74,6 @@
     // This value approximately overshoots to 1.5 times the original size.
     private static final float ENTER_ANIMATION_OVERSHOOT_TENSION = 4.9f;
 
-    private static final float INDICATOR_ROTATION = 180f;
-
     private static final RectF sTempRect = new RectF();
 
     private static final FloatProperty<PageIndicatorDots> CURRENT_POSITION =
@@ -112,11 +106,8 @@
             };
 
     private final Handler mDelayedPaginationFadeHandler = new Handler(Looper.getMainLooper());
-    private final Drawable mPageIndicatorDrawable;
     private final float mDotRadius;
     private final float mCircleGap;
-    private final float mPageIndicatorSize;
-    private final float mPageIndicatorRadius;
     private final boolean mIsRtl;
 
     private int mNumPages;
@@ -159,31 +150,14 @@
         mPaginationPaint.setStyle(Style.FILL);
         mPaginationPaint.setColor(Themes.getAttrColor(context, R.attr.folderPaginationColor));
         mDotRadius = getResources().getDimension(R.dimen.page_indicator_dot_size) / 2;
-
-        if (SHOW_DELIGHTFUL_PAGINATION.get()) {
-            mPageIndicatorSize = getResources().getDimension(
-                    R.dimen.page_indicator_size);
-            mPageIndicatorRadius = mPageIndicatorSize / 2;
-            mPageIndicatorDrawable = context.getDrawable(R.drawable.page_indicator);
-            mPageIndicatorDrawable.setBounds(0, 0, (int) mPageIndicatorSize,
-                    (int) mPageIndicatorSize);
-            mCircleGap = DOT_GAP_FACTOR_FLOAT * mDotRadius;
-
-        } else {
-            mPageIndicatorSize = 0;
-            mPageIndicatorRadius = 0;
-            mPageIndicatorDrawable = null;
-            mCircleGap = DOT_GAP_FACTOR * mDotRadius;
-        }
-        if (!SHOW_DELIGHTFUL_PAGINATION.get()) {
-            setOutlineProvider(new MyOutlineProver());
-        }
+        mCircleGap = DOT_GAP_FACTOR * mDotRadius;
+        setOutlineProvider(new MyOutlineProver());
         mIsRtl = Utilities.isRtl(getResources());
     }
 
     @Override
     public void setScroll(int currentScroll, int totalScroll) {
-        if (SHOW_DELIGHTFUL_PAGINATION.get() || SHOW_DOT_PAGINATION.get()) {
+        if (SHOW_DOT_PAGINATION.get()) {
             animatePaginationToAlpha(VISIBLE_ALPHA);
         }
 
@@ -197,16 +171,6 @@
         }
 
         mTotalScroll = totalScroll;
-        if (SHOW_DELIGHTFUL_PAGINATION.get()) {
-            mCurrentScroll = currentScroll;
-            invalidate();
-
-            if (mShouldAutoHide
-                    && (getScrollPerPage() == 0 || mCurrentScroll % getScrollPerPage() == 0)) {
-                hideAfterDelay();
-            }
-            return;
-        }
 
         int scrollPerPage = totalScroll / (mNumPages - 1);
         int pageToLeft = currentScroll / scrollPerPage;
@@ -404,122 +368,45 @@
             }
             for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) {
                 mPaginationPaint.setAlpha(i == mActivePage ? PAGE_INDICATOR_ALPHA : DOT_ALPHA);
-                if (SHOW_DELIGHTFUL_PAGINATION.get()) {
-                    if (i != mActivePage) {
-                        canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
-                                mPaginationPaint);
-                    } else {
-                        drawPageIndicator(canvas, mEntryAnimationRadiusFactors[i]);
-                    }
-                } else {
-                    canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
-                            mPaginationPaint);
-                }
+                canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
+                        mPaginationPaint);
                 x += circleGap;
             }
         } else {
             // Here we draw the dots
             mPaginationPaint.setAlpha(DOT_ALPHA);
             for (int i = 0; i < mNumPages; i++) {
-                if (SHOW_DELIGHTFUL_PAGINATION.get()) {
-                    canvas.drawCircle(x, y, getRadius(x), mPaginationPaint);
-                } else {
-                    canvas.drawCircle(x, y, mDotRadius, mPaginationPaint);
-                }
+                canvas.drawCircle(x, y, mDotRadius, mPaginationPaint);
                 x += circleGap;
             }
 
             // Here we draw the current page indicator
             mPaginationPaint.setAlpha(PAGE_INDICATOR_ALPHA);
-            if (SHOW_DELIGHTFUL_PAGINATION.get()) {
-                drawPageIndicator(canvas, 1);
-            } else {
-                canvas.drawRoundRect(getActiveRect(), mDotRadius, mDotRadius, mPaginationPaint);
-            }
+            canvas.drawRoundRect(getActiveRect(), mDotRadius, mDotRadius, mPaginationPaint);
         }
     }
 
-    /**
-     * Draws the page indicator, denoting the currently selected page
-     *
-     * @param canvas is used to draw the page indicator and to rotate it as we scroll
-     * @param scale  is used to set the scale of our canvas
-     */
-    private void drawPageIndicator(Canvas canvas, float scale) {
-        RectF currRect = getActiveRect();
-
-        // saves the canvas so we can later restore it to its original scale
-        canvas.save();
-
-        // Moves the canvas to start at the top left corner of the page indicator
-        canvas.translate(currRect.left, currRect.top);
-
-        // Scales the canvas in place to animate the indicator on entry
-        canvas.scale(scale, scale, mPageIndicatorRadius, mPageIndicatorRadius);
-
-        int scrollPerPage = getScrollPerPage();
-        // This IF is to avoid division by 0
-        if (scrollPerPage != 0) {
-            int delta = mCurrentScroll % scrollPerPage;
-            canvas.rotate((INDICATOR_ROTATION * delta) / scrollPerPage,
-                    mPageIndicatorRadius, mPageIndicatorRadius);
-        }
-
-        mPageIndicatorDrawable.draw(canvas);
-        canvas.restore();
-    }
-
-    /**
-     * Returns the radius of the circle based on how close the page indicator is to it
-     *
-     * @param dotPositionX is the position the dot is located at in the x-axis
-     */
-    private float getRadius(float dotPositionX) {
-
-        float startXIndicator =
-                ((getWidth() - (mNumPages * mCircleGap) + mDotRadius) / 2) - getOffset();
-        float indicatorPosition = startXIndicator + getIndicatorScrollDistance()
-                + mPageIndicatorRadius;
-
-        // If the indicator gets close enough to a dot then we change the radius
-        // of the dot based on how close the indicator is to it.
-        float dotDistance = Math.abs(indicatorPosition - dotPositionX);
-        if (dotDistance <= mCircleGap) {
-            return Utilities.mapToRange(dotDistance, 0, mCircleGap, 0f, mDotRadius,
-                    Interpolators.LINEAR);
-        }
-        return mDotRadius;
-    }
-
     private RectF getActiveRect() {
         float startCircle = (int) mCurrentPosition;
         float delta = mCurrentPosition - startCircle;
         float diameter = 2 * mDotRadius;
         float startX;
 
-        if (SHOW_DELIGHTFUL_PAGINATION.get()) {
-            startX = ((getWidth() - (mNumPages * mCircleGap) + mDotRadius) / 2) - getOffset();
-            sTempRect.top = (getHeight() - mPageIndicatorSize) * 0.5f;
-            sTempRect.bottom = (getHeight() + mPageIndicatorSize) * 0.5f;
-            sTempRect.left = startX + getIndicatorScrollDistance();
-            sTempRect.right = sTempRect.left + mPageIndicatorSize;
+        startX = ((getWidth() - (mNumPages * mCircleGap) + mDotRadius) / 2);
+        sTempRect.top = (getHeight() * 0.5f) - mDotRadius;
+        sTempRect.bottom = (getHeight() * 0.5f) + mDotRadius;
+        sTempRect.left = startX + (startCircle * mCircleGap);
+        sTempRect.right = sTempRect.left + diameter;
+
+        if (delta < SHIFT_PER_ANIMATION) {
+            // dot is capturing the right circle.
+            sTempRect.right += delta * mCircleGap * 2;
         } else {
-            startX = ((getWidth() - (mNumPages * mCircleGap) + mDotRadius) / 2);
-            sTempRect.top = (getHeight() * 0.5f) - mDotRadius;
-            sTempRect.bottom = (getHeight() * 0.5f) + mDotRadius;
-            sTempRect.left = startX + (startCircle * mCircleGap);
-            sTempRect.right = sTempRect.left + diameter;
+            // Dot is leaving the left circle.
+            sTempRect.right += mCircleGap;
 
-            if (delta < SHIFT_PER_ANIMATION) {
-                // dot is capturing the right circle.
-                sTempRect.right += delta * mCircleGap * 2;
-            } else {
-                // Dot is leaving the left circle.
-                sTempRect.right += mCircleGap;
-
-                delta -= SHIFT_PER_ANIMATION;
-                sTempRect.left += delta * mCircleGap * 2;
-            }
+            delta -= SHIFT_PER_ANIMATION;
+            sTempRect.left += delta * mCircleGap * 2;
         }
 
         if (mIsRtl) {
@@ -531,29 +418,6 @@
         return sTempRect;
     }
 
-    /**
-     * The offset between the radius of the dot and the midpoint of the indicator so that
-     * the indicator is centered in with the indicator circles
-     */
-    private float getOffset() {
-        return mPageIndicatorRadius - mDotRadius;
-    }
-
-    /**
-     * Returns an int that is the amount we need to scroll per page
-     */
-    private int getScrollPerPage() {
-        return mNumPages > 1 ? mTotalScroll / (mNumPages - 1) : 0;
-    }
-
-    /**
-     * The current scroll adjusted for the distance the indicator needs to travel on the screen
-     */
-    private float getIndicatorScrollDistance() {
-        int scrollPerPage = getScrollPerPage();
-        return scrollPerPage != 0 ? ((float) mCurrentScroll / scrollPerPage) * mCircleGap : 0;
-    }
-
     private class MyOutlineProver extends ViewOutlineProvider {
 
         @Override
diff --git a/src/com/android/launcher3/statemanager/BaseState.java b/src/com/android/launcher3/statemanager/BaseState.java
index 32378b8..2390425 100644
--- a/src/com/android/launcher3/statemanager/BaseState.java
+++ b/src/com/android/launcher3/statemanager/BaseState.java
@@ -18,7 +18,7 @@
 import android.content.Context;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
+import com.android.launcher3.views.ActivityContext;
 
 /**
  * Interface representing a state of a StatefulActivity
@@ -37,7 +37,7 @@
     /**
      * @return How long the animation to this state should take (or from this state to NORMAL).
      */
-    <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable>
+    <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
     int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState);
 
     /**
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 6cb021b..96ae4a3 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -44,6 +44,7 @@
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.TouchUtil;
 
 /**
  * Helper class to handle touch on empty space in workspace and show options popup on long press
@@ -105,6 +106,11 @@
             if (handleLongPress) {
                 mLongPressState = STATE_REQUESTED;
                 mTouchDownPoint.set(ev.getX(), ev.getY());
+                // Mouse right button's ACTION_DOWN should immediately show menu
+                if (TouchUtil.isMouseRightClickDownOrMove(ev)) {
+                    maybeShowMenu();
+                    return true;
+                }
             }
 
             mWorkspace.onTouchEvent(ev);
@@ -185,6 +191,10 @@
 
     @Override
     public void onLongPress(MotionEvent event) {
+        maybeShowMenu();
+    }
+
+    private void maybeShowMenu() {
         if (mLongPressState == STATE_REQUESTED) {
             TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Workspace.longPress");
             if (canHandleLongPress()) {
diff --git a/src/com/android/launcher3/util/TouchUtil.java b/src/com/android/launcher3/util/TouchUtil.java
new file mode 100644
index 0000000..b18a2ef
--- /dev/null
+++ b/src/com/android/launcher3/util/TouchUtil.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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.util;
+
+import android.view.InputDevice;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+
+/** Util class for touch event. */
+public final class TouchUtil {
+
+    private TouchUtil() {}
+
+    /**
+     * Detect ACTION_DOWN or ACTION_MOVE from mouse right button. Note that we cannot detect
+     * ACTION_UP from mouse's right button because, in that case,
+     * {@link MotionEvent#getButtonState()} returns 0 for any mouse button (right, middle, right).
+     */
+    public static boolean isMouseRightClickDownOrMove(@NonNull MotionEvent event) {
+        return event.isFromSource(InputDevice.SOURCE_MOUSE)
+                && ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0);
+    }
+}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index dd5b22e..28085e1 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -17,23 +17,41 @@
 
 import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
+import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
+import android.app.ActivityOptions;
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.LauncherApps;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
+import android.os.StrictMode;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
 import android.view.WindowInsets;
 import android.view.WindowInsetsController;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.Toast;
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
@@ -41,20 +59,30 @@
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.util.OnboardingPrefs;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.ViewCache;
 
+import java.util.List;
+
 /**
  * An interface to be used along with a context for various activities in Launcher. This allows a
  * generic class to depend on Context subclass instead of an Activity.
  */
 public interface ActivityContext {
 
+    String TAG = "ActivityContext";
+
     default boolean finishAutoCancelActionMode() {
         return false;
     }
@@ -117,6 +145,28 @@
 
     DeviceProfile getDeviceProfile();
 
+    /** Registered {@link OnDeviceProfileChangeListener} instances. */
+    List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners();
+
+    /** Notifies listeners of a {@link DeviceProfile} change. */
+    default void dispatchDeviceProfileChanged() {
+        DeviceProfile deviceProfile = getDeviceProfile();
+        List<OnDeviceProfileChangeListener> listeners = getOnDeviceProfileChangeListeners();
+        for (int i = listeners.size() - 1; i >= 0; i--) {
+            listeners.get(i).onDeviceProfileChanged(deviceProfile);
+        }
+    }
+
+    /** Register listener for {@link DeviceProfile} changes. */
+    default void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
+        getOnDeviceProfileChangeListeners().add(listener);
+    }
+
+    /** Unregister listener for {@link DeviceProfile} changes. */
+    default void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
+        getOnDeviceProfileChangeListeners().remove(listener);
+    }
+
     default ViewCache getViewCache() {
         return new ViewCache();
     }
@@ -162,32 +212,6 @@
         return false;
     }
 
-    /**
-     * Returns the ActivityContext associated with the given Context, or throws an exception if
-     * the Context is not associated with any ActivityContext.
-     */
-    static <T extends Context & ActivityContext> T lookupContext(Context context) {
-        T activityContext = lookupContextNoThrow(context);
-        if (activityContext == null) {
-            throw new IllegalArgumentException("Cannot find ActivityContext in parent tree");
-        }
-        return activityContext;
-    }
-
-    /**
-     * Returns the ActivityContext associated with the given Context, or null if
-     * the Context is not associated with any ActivityContext.
-     */
-    static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) {
-        if (context instanceof ActivityContext) {
-            return (T) context;
-        } else if (context instanceof ContextWrapper) {
-            return lookupContextNoThrow(((ContextWrapper) context).getBaseContext());
-        } else {
-            return null;
-        }
-    }
-
     default View.OnClickListener getItemOnClickListener() {
         return v -> {
             // No op.
@@ -256,4 +280,187 @@
             });
         }
     }
+
+    /**
+     * Safely starts an activity.
+     *
+     * @param v View starting the activity.
+     * @param intent Base intent being launched.
+     * @param item Item associated with the view.
+     * @return {@code true} if the activity starts successfully.
+     */
+    default boolean startActivitySafely(
+            View v, Intent intent, @Nullable ItemInfo item) {
+
+        Context context = (Context) this;
+        if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
+            Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
+            return false;
+        }
+
+        Bundle optsBundle = (v != null) ? getActivityLaunchOptions(v, item).toBundle() : null;
+        UserHandle user = item == null ? null : item.user;
+
+        // Prepare intent
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (v != null) {
+            intent.setSourceBounds(Utilities.getViewBounds(v));
+        }
+        try {
+            boolean isShortcut = (item instanceof WorkspaceItemInfo)
+                    && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+                    || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
+                    && !((WorkspaceItemInfo) item).isPromise();
+            if (isShortcut) {
+                // Shortcuts need some special checks due to legacy reasons.
+                startShortcutIntentSafely(intent, optsBundle, item);
+            } else if (user == null || user.equals(Process.myUserHandle())) {
+                // Could be launching some bookkeeping activity
+                context.startActivity(intent, optsBundle);
+            } else {
+                context.getSystemService(LauncherApps.class).startMainActivity(
+                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
+            }
+            if (item != null) {
+                InstanceId instanceId = new InstanceIdSequence().newInstanceId();
+                logAppLaunch(getStatsLogManager(), item, instanceId);
+            }
+            return true;
+        } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
+            Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
+        }
+        return false;
+    }
+
+    /** Returns {@code true} if an app launch is blocked due to safe mode. */
+    default boolean isAppBlockedForSafeMode() {
+        return false;
+    }
+
+    /**
+     * Creates and logs a new app launch event.
+     */
+    default void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info,
+            InstanceId instanceId) {
+        statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId)
+                .log(LAUNCHER_APP_LAUNCH_TAP);
+    }
+
+    /**
+     * Returns launch options for an Activity.
+     *
+     * @param v View initiating a launch.
+     * @param item Item associated with the view.
+     */
+    default ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
+        int left = 0, top = 0;
+        int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
+        if (v instanceof BubbleTextView) {
+            // Launch from center of icon, not entire view
+            Drawable icon = ((BubbleTextView) v).getIcon();
+            if (icon != null) {
+                Rect bounds = icon.getBounds();
+                left = (width - bounds.width()) / 2;
+                top = v.getPaddingTop();
+                width = bounds.width();
+                height = bounds.height();
+            }
+        }
+        ActivityOptions options =
+                ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
+
+        options.setLaunchDisplayId(
+                (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
+                        : Display.DEFAULT_DISPLAY);
+        RunnableList callback = new RunnableList();
+        return new ActivityOptionsWrapper(options, callback);
+    }
+
+    /**
+     * Safely launches an intent for a shortcut.
+     *
+     * @param intent Intent to start.
+     * @param optsBundle Optional launch arguments.
+     * @param info Shortcut information.
+     */
+    default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
+        try {
+            StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
+            try {
+                // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
+                // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
+                // is enabled by default on NYC.
+                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
+                        .penaltyLog().build());
+
+                if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                    String id = ((WorkspaceItemInfo) info).getDeepShortcutId();
+                    String packageName = intent.getPackage();
+                    startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
+                } else {
+                    // Could be launching some bookkeeping activity
+                    ((Context) this).startActivity(intent, optsBundle);
+                }
+            } finally {
+                StrictMode.setVmPolicy(oldPolicy);
+            }
+        } catch (SecurityException e) {
+            if (!onErrorStartingShortcut(intent, info)) {
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * A wrapper around the platform method with Launcher specific checks.
+     */
+    default void startShortcut(String packageName, String id, Rect sourceBounds,
+            Bundle startActivityOptions, UserHandle user) {
+        if (GO_DISABLE_WIDGETS) {
+            return;
+        }
+        try {
+            ((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id,
+                    sourceBounds, startActivityOptions, user);
+        } catch (SecurityException | IllegalStateException e) {
+            Log.e(TAG, "Failed to start shortcut", e);
+        }
+    }
+
+    /**
+     * Invoked when a shortcut fails to launch.
+     * @param intent Shortcut intent that failed to start.
+     * @param info Shortcut information.
+     * @return {@code true} if the error is handled by this callback.
+     */
+    default boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
+        return false;
+    }
+
+    /**
+     * Returns the ActivityContext associated with the given Context, or throws an exception if
+     * the Context is not associated with any ActivityContext.
+     */
+    static <T extends Context & ActivityContext> T lookupContext(Context context) {
+        T activityContext = lookupContextNoThrow(context);
+        if (activityContext == null) {
+            throw new IllegalArgumentException("Cannot find ActivityContext in parent tree");
+        }
+        return activityContext;
+    }
+
+    /**
+     * Returns the ActivityContext associated with the given Context, or null if
+     * the Context is not associated with any ActivityContext.
+     */
+    static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) {
+        if (context instanceof ActivityContext) {
+            return (T) context;
+        } else if (context instanceof ContextWrapper) {
+            return lookupContextNoThrow(((ContextWrapper) context).getBaseContext());
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/views/AppLauncher.java b/src/com/android/launcher3/views/AppLauncher.java
deleted file mode 100644
index 19e66ab..0000000
--- a/src/com/android/launcher3/views/AppLauncher.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
-import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
-
-import android.app.ActivityOptions;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Process;
-import android.os.StrictMode;
-import android.os.UserHandle;
-import android.util.Log;
-import android.view.Display;
-import android.view.View;
-import android.widget.Toast;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.logging.InstanceId;
-import com.android.launcher3.logging.InstanceIdSequence;
-import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.util.ActivityOptionsWrapper;
-import com.android.launcher3.util.PackageManagerHelper;
-import com.android.launcher3.util.RunnableList;
-
-/** An {@link ActivityContext} that can also launch app activities and shortcuts safely. */
-public interface AppLauncher extends ActivityContext {
-
-    String TAG = "AppLauncher";
-
-    /**
-     * Safely starts an activity.
-     *
-     * @param v View starting the activity.
-     * @param intent Base intent being launched.
-     * @param item Item associated with the view.
-     * @return {@code true} if the activity starts successfully.
-     */
-    default boolean startActivitySafely(
-            View v, Intent intent, @Nullable ItemInfo item) {
-
-        Context context = (Context) this;
-        if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
-            Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
-            return false;
-        }
-
-        Bundle optsBundle = (v != null) ? getActivityLaunchOptions(v, item).toBundle() : null;
-        UserHandle user = item == null ? null : item.user;
-
-        // Prepare intent
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        if (v != null) {
-            intent.setSourceBounds(Utilities.getViewBounds(v));
-        }
-        try {
-            boolean isShortcut = (item instanceof WorkspaceItemInfo)
-                    && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
-                    || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
-                    && !((WorkspaceItemInfo) item).isPromise();
-            if (isShortcut) {
-                // Shortcuts need some special checks due to legacy reasons.
-                startShortcutIntentSafely(intent, optsBundle, item);
-            } else if (user == null || user.equals(Process.myUserHandle())) {
-                // Could be launching some bookkeeping activity
-                context.startActivity(intent, optsBundle);
-            } else {
-                context.getSystemService(LauncherApps.class).startMainActivity(
-                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
-            }
-            if (item != null) {
-                InstanceId instanceId = new InstanceIdSequence().newInstanceId();
-                logAppLaunch(getStatsLogManager(), item, instanceId);
-            }
-            return true;
-        } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
-            Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
-        }
-        return false;
-    }
-
-    /** Returns {@code true} if an app launch is blocked due to safe mode. */
-    default boolean isAppBlockedForSafeMode() {
-        return false;
-    }
-
-    /**
-     * Creates and logs a new app launch event.
-     */
-    default void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info,
-            InstanceId instanceId) {
-        statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId)
-                .log(LAUNCHER_APP_LAUNCH_TAP);
-    }
-
-    /**
-     * Returns launch options for an Activity.
-     *
-     * @param v View initiating a launch.
-     * @param item Item associated with the view.
-     */
-    default ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
-        int left = 0, top = 0;
-        int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
-        if (v instanceof BubbleTextView) {
-            // Launch from center of icon, not entire view
-            Drawable icon = ((BubbleTextView) v).getIcon();
-            if (icon != null) {
-                Rect bounds = icon.getBounds();
-                left = (width - bounds.width()) / 2;
-                top = v.getPaddingTop();
-                width = bounds.width();
-                height = bounds.height();
-            }
-        }
-        ActivityOptions options =
-                ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
-
-        options.setLaunchDisplayId(
-                (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
-                        : Display.DEFAULT_DISPLAY);
-        RunnableList callback = new RunnableList();
-        return new ActivityOptionsWrapper(options, callback);
-    }
-
-    /**
-     * Safely launches an intent for a shortcut.
-     *
-     * @param intent Intent to start.
-     * @param optsBundle Optional launch arguments.
-     * @param info Shortcut information.
-     */
-    default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
-        try {
-            StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
-            try {
-                // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
-                // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
-                // is enabled by default on NYC.
-                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
-                        .penaltyLog().build());
-
-                if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                    String id = ((WorkspaceItemInfo) info).getDeepShortcutId();
-                    String packageName = intent.getPackage();
-                    startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
-                } else {
-                    // Could be launching some bookkeeping activity
-                    ((Context) this).startActivity(intent, optsBundle);
-                }
-            } finally {
-                StrictMode.setVmPolicy(oldPolicy);
-            }
-        } catch (SecurityException e) {
-            if (!onErrorStartingShortcut(intent, info)) {
-                throw e;
-            }
-        }
-    }
-
-    /**
-     * A wrapper around the platform method with Launcher specific checks.
-     */
-    default void startShortcut(String packageName, String id, Rect sourceBounds,
-            Bundle startActivityOptions, UserHandle user) {
-        if (GO_DISABLE_WIDGETS) {
-            return;
-        }
-        try {
-            ((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id,
-                    sourceBounds, startActivityOptions, user);
-        } catch (SecurityException | IllegalStateException e) {
-            Log.e(TAG, "Failed to start shortcut", e);
-        }
-    }
-
-    /**
-     * Invoked when a shortcut fails to launch.
-     * @param intent Shortcut intent that failed to start.
-     * @param info Shortcut information.
-     * @return {@code true} if the error is handled by this callback.
-     */
-    default boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
-        return false;
-    }
-}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 622516f..5b57e22 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -139,12 +139,12 @@
         mTargetRect.roundOut(outPos);
     }
 
-    public static OptionsPopupView show(AppLauncher launcher, RectF targetRect,
+    public static OptionsPopupView show(ActivityContext launcher, RectF targetRect,
             List<OptionItem> items, boolean shouldAddArrow) {
         return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */);
     }
 
-    public static OptionsPopupView show(AppLauncher launcher, RectF targetRect,
+    public static OptionsPopupView show(ActivityContext launcher, RectF targetRect,
             List<OptionItem> items, boolean shouldAddArrow, int width) {
         OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
                 .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
index a581f91..772a995 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -20,11 +20,11 @@
 
 import android.content.Context;
 
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.ActivityContext;
 
 /**
  * Definition for AllApps state
@@ -40,7 +40,7 @@
     }
 
     @Override
-    public <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable>
+    public <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
     int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState) {
         return isToState
                 ? context.getDeviceProfile().allAppsOpenDuration
diff --git a/tests/src/com/android/launcher3/util/ActivityContextWrapper.java b/tests/src/com/android/launcher3/util/ActivityContextWrapper.java
index 2618a2e..191d284 100644
--- a/tests/src/com/android/launcher3/util/ActivityContextWrapper.java
+++ b/tests/src/com/android/launcher3/util/ActivityContextWrapper.java
@@ -20,15 +20,21 @@
 import android.view.ContextThemeWrapper;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * {@link ContextWrapper} with internal Launcher interface for testing
  */
 public class ActivityContextWrapper extends ContextThemeWrapper implements ActivityContext {
 
+    private final List<OnDeviceProfileChangeListener> mDpChangeListeners = new ArrayList<>();
+
     private final DeviceProfile mProfile;
     private final MyDragLayer mMyDragLayer;
 
@@ -44,6 +50,11 @@
     }
 
     @Override
+    public List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners() {
+        return mDpChangeListeners;
+    }
+
+    @Override
     public DeviceProfile getDeviceProfile() {
         return mProfile;
     }
diff --git a/tests/src/com/android/launcher3/util/TouchUtilTest.kt b/tests/src/com/android/launcher3/util/TouchUtilTest.kt
new file mode 100644
index 0000000..d6c6e91
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/TouchUtilTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 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.util
+
+import android.view.InputDevice
+import android.view.MotionEvent
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Unit tests for [TouchUtil] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TouchUtilTest {
+
+    @Test
+    fun isMouseRightClickDownOrMove_onMouseRightButton_returnsTrue() {
+        val ev = MotionEvent.obtain(200, 300, MotionEvent.ACTION_MOVE, 1.0f, 0.0f, 0)
+        ev.source = InputDevice.SOURCE_MOUSE
+        ev.buttonState = MotionEvent.BUTTON_SECONDARY
+
+        assertThat(TouchUtil.isMouseRightClickDownOrMove(ev)).isTrue()
+    }
+
+    @Test
+    fun isMouseRightClickDownOrMove_onMouseLeftButton_returnsFalse() {
+        val ev = MotionEvent.obtain(200, 300, MotionEvent.ACTION_MOVE, 1.0f, 0.0f, 0)
+        ev.source = InputDevice.SOURCE_MOUSE
+        ev.buttonState = MotionEvent.BUTTON_PRIMARY
+
+        assertThat(TouchUtil.isMouseRightClickDownOrMove(ev)).isFalse()
+    }
+
+    @Test
+    fun isMouseRightClickDownOrMove_onMouseTertiaryButton_returnsFalse() {
+        val ev = MotionEvent.obtain(200, 300, MotionEvent.ACTION_MOVE, 1.0f, 0.0f, 0)
+        ev.source = InputDevice.SOURCE_MOUSE
+        ev.buttonState = MotionEvent.BUTTON_TERTIARY
+
+        assertThat(TouchUtil.isMouseRightClickDownOrMove(ev)).isFalse()
+    }
+
+    @Test
+    fun isMouseRightClickDownOrMove_onDpadRightButton_returnsFalse() {
+        val ev = MotionEvent.obtain(200, 300, MotionEvent.ACTION_MOVE, 1.0f, 0.0f, 0)
+        ev.source = InputDevice.SOURCE_DPAD
+        ev.buttonState = MotionEvent.BUTTON_SECONDARY
+
+        assertThat(TouchUtil.isMouseRightClickDownOrMove(ev)).isFalse()
+    }
+}